浏览代码

V1.3.0

从零开始学习音视频编程技术(十八) 录屏软件开发之编码AAC
叶海辉 6 年之前
父节点
当前提交
40d9aed306
共有 11 个文件被更改,包括 731 次插入229 次删除
  1. 11 4
      VideoRecorder.pro
  2. 0 223
      main.cpp
  3. 155 0
      src/audio/AACEncoder.cpp
  4. 62 0
      src/audio/AACEncoder.h
  5. 197 0
      src/audio/getaudiothread.cpp
  6. 75 0
      src/audio/getaudiothread.h
  7. 28 0
      src/main.cpp
  8. 92 0
      src/mainwindow.cpp
  9. 42 0
      src/mainwindow.h
  10. 67 0
      src/mainwindow.ui
  11. 2 2
      说明.txt

+ 11 - 4
VideoRecorder.pro

@@ -12,14 +12,21 @@ TARGET = VideoRecorder
 TEMPLATE = app
 
 
-SOURCES += main.cpp
+SOURCES += src/main.cpp \
+    src/mainwindow.cpp \
+    src/audio/AACEncoder.cpp \
+    src/audio/getaudiothread.cpp
 
-HEADERS  +=
+HEADERS  += \
+    src/mainwindow.h \
+    src/audio/AACEncoder.h \
+    src/audio/getaudiothread.h
 
-FORMS    +=
+FORMS    += \
+    src/mainwindow.ui
 
 INCLUDEPATH += $$PWD/ffmpeg/include \
-                $$PWD/src
+               $$PWD/src
 
 LIBS += $$PWD/ffmpeg/lib/avcodec.lib \
         $$PWD/ffmpeg/lib/avdevice.lib \

+ 0 - 223
main.cpp

@@ -1,223 +0,0 @@
-
-/**
- * 叶海辉
- * QQ群121376426
- * http://blog.yundiantech.com/
- */
-
-#include <stdio.h>
-
-extern "C"
-{
-#include "libavcodec/avcodec.h"
-#include "libavformat/avformat.h"
-#include "libswscale/swscale.h"
-#include "libavdevice/avdevice.h"
-}
-
-//'1' Use Dshow
-//'0' Use VFW
-#define USE_DSHOW 0
-
-
-//Show Dshow Device
-void show_dshow_device(){
-    AVFormatContext *pFormatCtx = avformat_alloc_context();
-    AVDictionary* options = NULL;
-    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");
-}
-
-//Show Dshow Device Option
-void show_dshow_device_option(){
-    AVFormatContext *pFormatCtx = avformat_alloc_context();
-    AVDictionary* options = NULL;
-    av_dict_set(&options,"list_options","true",0);
-    AVInputFormat *iformat = av_find_input_format("dshow");
-    printf("========Device Option Info======\n");
-    avformat_open_input(&pFormatCtx,"video=Integrated Camera",iformat,&options);
-    printf("================================\n");
-}
-
-//Show VFW Device
-void show_vfw_device(){
-    AVFormatContext *pFormatCtx = avformat_alloc_context();
-    AVInputFormat *iformat = av_find_input_format("vfwcap");
-    printf("========VFW Device Info======\n");
-    avformat_open_input(&pFormatCtx,"list",iformat,NULL);
-    printf("=============================\n");
-}
-
-//Show AVFoundation Device
-void show_avfoundation_device(){
-    AVFormatContext *pFormatCtx = avformat_alloc_context();
-    AVDictionary* options = NULL;
-    av_dict_set(&options,"list_devices","true",0);
-    AVInputFormat *iformat = av_find_input_format("avfoundation");
-    printf("==AVFoundation Device Info===\n");
-    avformat_open_input(&pFormatCtx,"",iformat,&options);
-    printf("=============================\n");
-}
-
-#define USE_DSHOW 1
-int main(int argc, char* argv[])
-{
-
-    AVFormatContext	*pFormatCtx;
-    int				i, videoindex;
-    AVCodecContext	*pCodecCtx;
-    AVCodec			*pCodec;
-
-    av_register_all();
-    avformat_network_init();
-    avdevice_register_all();//Register Device
-
-
-    //Show Dshow Device
-    show_dshow_device();
-    //Show Device Options
-//    show_dshow_device_option();
-    //Show VFW Options
-//    show_vfw_device();
-
-    pFormatCtx = avformat_alloc_context();
-
-#if USE_DSHOW
-    //Use dshow
-    //
-    //这里需要先安装 screen-capture-recorder 才能使用dshow采集屏幕
-    //screen-capture-recorder
-    //Website: http://sourceforge.net/projects/screencapturer/
-    //
-    AVInputFormat *ifmt=av_find_input_format("dshow");
-    if(avformat_open_input(&pFormatCtx,"video=screen-capture-recorder",ifmt,NULL)!=0){
-        printf("Couldn't open input stream.\n");
-        return -1;
-    }
-#else
-    //Use gdigrab
-    AVDictionary* options = NULL;
-    //Set some options
-    //grabbing frame rate
-    //av_dict_set(&options,"framerate","5",0);
-    //The distance from the left edge of the screen or desktop
-    //av_dict_set(&options,"offset_x","20",0);
-    //The distance from the top edge of the screen or desktop
-    //av_dict_set(&options,"offset_y","40",0);
-    //Video frame size. The default is to capture the full screen
-    //av_dict_set(&options,"video_size","640x480",0);
-    AVInputFormat *ifmt=av_find_input_format("gdigrab");
-    if(avformat_open_input(&pFormatCtx,"desktop",ifmt,&options)!=0){
-        printf("Couldn't open input stream.\n");
-        return -1;
-    }
-
-#endif
-
-    if(avformat_find_stream_info(pFormatCtx,NULL)<0)
-    {
-        printf("Couldn't find stream information.\n");
-        return -1;
-    }
-
-    videoindex=-1;
-
-    for(i=0; i<pFormatCtx->nb_streams; i++)
-    {
-        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
-        {
-            videoindex=i;
-        }
-    }
-
-    if(videoindex==-1)
-    {
-        printf("Couldn't find a video stream.\n");
-        return -1;
-    }
-
-    pCodecCtx=pFormatCtx->streams[videoindex]->codec;
-    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
-    
-    if(pCodec==NULL)
-    {
-        printf("Codec not found.\n");
-        return -1;
-    }
-
-    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
-    {
-        printf("Could not open codec.\n");
-        return -1;
-    }
-
-    AVFrame	*pFrame,*pFrameYUV;
-    pFrame=av_frame_alloc();
-    pFrameYUV=av_frame_alloc();
-    uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
-    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
-
-    int ret, got_picture;
-
-    AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
-
-    FILE *fp_yuv=fopen("output.yuv","wb");
-
-    struct SwsContext *img_convert_ctx;
-    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
-
-    ///这里打印出视频的宽高
-    fprintf(stderr,"w= %d h= %d\n",pCodecCtx->width, pCodecCtx->height);
-
-    ///我们就读取100张图像
-    for(int i=0;i<100;i++)
-    {
-        if(av_read_frame(pFormatCtx, packet) < 0)
-        {
-            break;
-        }
-
-        if(packet->stream_index==videoindex)
-        {
-            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
-
-            if(ret < 0){
-                printf("Decode Error.\n");
-                return -1;
-            }
-
-            if(got_picture)
-            {
-
-                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
-
-
-                int y_size=pCodecCtx->width*pCodecCtx->height;
-                fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
-                fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
-                fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
-
-            }
-        }
-        av_free_packet(packet);
-    }
-
-    sws_freeContext(img_convert_ctx);
-
-
-    fclose(fp_yuv);
-
-
-    av_free(out_buffer);
-    av_free(pFrameYUV);
-    avcodec_close(pCodecCtx);
-    avformat_close_input(&pFormatCtx);
-
-    return 0;
-}
-
-
-

+ 155 - 0
src/audio/AACEncoder.cpp

@@ -0,0 +1,155 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include "aacencoder.h"
+
+extern "C"
+{
+#include "libavcodec\avcodec.h"
+#include "libavformat\avformat.h"
+#include "libswscale\swscale.h"
+}
+
+AACEncoder::AACEncoder()
+{
+
+}
+
+AACEncoder::~AACEncoder()
+{
+
+}
+
+void AACEncoder::startEncode()
+{
+    start();
+}
+
+void AACEncoder::inputPcmBuffer(uint8_t *buffer, int size)
+{
+    FrameDataNode node;
+    node.size = size;
+    node.buffer = buffer;
+
+    mMutex.lock();
+    mPcmBufferList.append(node);
+    mMutex.unlock();
+}
+
+void AACEncoder::run()
+{
+    AVCodecContext* pCodecCtx;
+    AVCodec* aCodec;
+
+    uint8_t* frame_buf;
+    AVFrame* frame;
+    int ONEFrameSize;
+
+    //查找h264编码器
+    aCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
+    if(!aCodec)
+    {
+      fprintf(stderr, "aac codec not found\n");
+      exit(1);
+    }
+
+    pCodecCtx = avcodec_alloc_context3(aCodec);
+    pCodecCtx->codec_id = AV_CODEC_ID_AAC;
+    pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
+    pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
+    pCodecCtx->sample_rate= 44100;
+    pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
+    pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
+    pCodecCtx->bit_rate = 64000;
+
+
+    aCodec = avcodec_find_encoder(pCodecCtx->codec_id);
+    if (!aCodec)
+    {
+        printf("没有找到合适的编码器!\n");
+        return;
+    }
+    if (avcodec_open2(pCodecCtx, aCodec,NULL) < 0)
+    {
+        printf("编码器打开失败!\n");
+        return;
+    }
+    frame = avcodec_alloc_frame();
+    frame->nb_samples = pCodecCtx->frame_size;
+    frame->format = pCodecCtx->sample_fmt;
+
+    ONEFrameSize = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
+    frame_buf = (uint8_t *)av_malloc(ONEFrameSize);
+    avcodec_fill_audio_frame(frame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, ONEFrameSize, 1);
+
+
+    AVPacket pkt;
+    av_new_packet(&pkt,ONEFrameSize);
+
+    FILE *aacFp = fopen("out.aac","wb");
+
+    uint8_t * mAacBuffer = (uint8_t * )malloc(4096*100);
+    int mAacBufferIndex = 0;
+    int mAacBufferSize = 0;
+
+    while(1)
+    {
+        if (mPcmBufferList.isEmpty())
+        {
+            msleep(10);
+            continue;
+        }
+
+        mMutex.lock();
+        FrameDataNode node = mPcmBufferList.takeFirst(); //取出1帧yuv数据
+        mMutex.unlock();
+
+        memcpy(mAacBuffer+mAacBufferSize,node.buffer,node.size);
+        mAacBufferSize += node.size;
+        free(node.buffer);
+
+        /// 每次传递给编码器的数据大小都要是 上面获取到的 "ONEFrameSize"
+        /// 因此需要下面的循环
+        while(1)
+        {
+            int size = mAacBufferSize - mAacBufferIndex;
+            if (size < ONEFrameSize) //不够编码1帧了
+            {
+                memcpy(mAacBuffer,mAacBuffer+mAacBufferIndex,size);
+                mAacBufferIndex = 0;
+                mAacBufferSize = size;
+                break;
+            }
+
+            frame->data[0] = mAacBuffer+mAacBufferIndex;  //采样信号
+            mAacBufferIndex += ONEFrameSize;
+
+            int got_frame=0;
+
+            //编码
+            int ret = avcodec_encode_audio2(pCodecCtx, &pkt,frame, &got_frame);
+            if (got_frame==1)
+            {
+                /// 编码后的数据是带ADTS头的 因此写入文件后 可以直接用播放器播放
+                fwrite(pkt.data,1,pkt.size,aacFp);
+
+                av_free_packet(&pkt);
+            }
+        }
+    }
+
+    //清理
+    av_free(frame);
+    av_free(frame_buf);
+
+    free(mAacBuffer);
+
+    fclose(aacFp);
+
+    avcodec_close(pCodecCtx);
+
+}
+

+ 62 - 0
src/audio/AACEncoder.h

@@ -0,0 +1,62 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef AACENCODER_H
+#define AACENCODER_H
+
+#include <QThread>
+#include <QMutex>
+
+extern "C"
+{
+    #include "libavcodec/avcodec.h"
+    #include "libavformat/avformat.h"
+    #include "libswscale/swscale.h"
+    #include "libavdevice/avdevice.h"
+}
+
+/// 编码aac的线程  这里把编码和采集分开 放到单独的线程 是因为编码也比较耗时
+
+struct FrameDataNode
+{
+    uint8_t * buffer;
+    int size;
+
+    FrameDataNode()
+    {
+        buffer = NULL;
+        size = 0;
+    }
+};
+
+class AACEncoder : public QThread
+{
+    Q_OBJECT
+
+public:
+    explicit AACEncoder();
+    ~AACEncoder();
+
+    void startEncode();
+
+    /**
+     * @brief inputPcmBuffer 输入需要编码的PCM数据
+     * @param buffer
+     * @param size
+     * @param time
+     */
+    void inputPcmBuffer(uint8_t *buffer, int size);
+
+protected:
+    void run();
+
+private:
+    QList<FrameDataNode> mPcmBufferList; //PCM数据队列
+    QMutex mMutex;
+
+};
+
+#endif // AACENCODER_H

+ 197 - 0
src/audio/getaudiothread.cpp

@@ -0,0 +1,197 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include "getaudiothread.h"
+
+#include <QTimer>
+#include <QDateTime>
+#include <QDebug>
+
+#include <windows.h>
+
+GetAudioThread::GetAudioThread()
+{
+    m_isRun = false;
+
+    pFormatCtx = NULL;
+    out_buffer = NULL;
+
+    m_pause = false;
+
+    mAACEncoder = new AACEncoder;
+}
+
+GetAudioThread::~GetAudioThread()
+{
+
+}
+
+ErroCode GetAudioThread::init(QString audioDevName)
+{
+
+    AVCodec			*aCodec = NULL;
+
+    pFormatCtx = avformat_alloc_context();
+
+    AVInputFormat *ifmt = av_find_input_format("dshow"); //使用dshow
+
+    QString audioDevOption = QString("audio=%1").arg(audioDevName);
+
+    if(avformat_open_input(&pFormatCtx,audioDevOption.toUtf8(),ifmt,NULL)!=0){
+        fprintf(stderr,"Couldn't open input stream audio.\n");
+        return AudioOpenFailed;
+    }
+
+    audioindex = -1;
+    aCodecCtx = NULL;
+
+    for(i=0; i<pFormatCtx->nb_streams; i++)
+        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
+        {
+            audioindex=i;
+            break;
+        }
+    if(audioindex==-1)
+    {
+        printf("Didn't find a video stream.\n");
+        return AudioOpenFailed;
+    }
+
+    aCodecCtx = pFormatCtx->streams[audioindex]->codec;
+
+    aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
+    if(aCodec == NULL)
+    {
+        printf("audio Codec not found.\n");
+        return AudioDecoderOpenFailed;
+    }
+
+    if(avcodec_open2(aCodecCtx, aCodec,NULL)<0)
+    {
+        printf("Could not open video codec.\n");
+        return AudioDecoderOpenFailed;
+    }
+
+//    qDebug()<<"audio info:";
+//    qDebug()<<"audio info:"<<aCodecCtx->bit_rate<<aCodecCtx->sample_fmt<<aCodecCtx->bit_rate<<aCodecCtx->sample_rate<<aCodecCtx->channels;
+
+    aFrame = avcodec_alloc_frame();
+
+    return SUCCEED;
+}
+
+void GetAudioThread::deInit()
+{
+    if (out_buffer)
+    {
+        av_free(out_buffer);
+        out_buffer = NULL;
+    }
+
+    if (aFrame)
+    {
+        av_free(aFrame);
+        aFrame = NULL;
+    }
+
+    avformat_close_input(&pFormatCtx);
+
+    avformat_free_context(pFormatCtx);
+
+}
+
+void GetAudioThread::startRecord()
+{
+    m_isRun = true;
+    start();
+
+    if (mAACEncoder != NULL)
+        mAACEncoder->startEncode();
+
+}
+
+void GetAudioThread::pauseRecord()
+{
+    m_pause = true;
+}
+
+void GetAudioThread::restoreRecord()
+{
+    m_pause = false;
+}
+
+void GetAudioThread::stopRecord()
+{
+    m_pause = false;
+    m_isRun = false;
+}
+
+FILE *pcmFp = fopen("out.pcm","wb");
+
+void GetAudioThread::run()
+{
+    int ret, got_frame;
+
+    AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
+
+    while(m_isRun)
+    {
+
+        if (av_read_frame(pFormatCtx, packet)<0)
+        {
+            qDebug()<<"read failed!";
+            msleep(10);
+            continue;
+        }
+
+        if (m_pause)
+        {
+            av_free_packet(packet);
+            msleep(10);
+            continue;
+        }
+//qDebug()<<packet->stream_index << audioindex;
+        if(packet->stream_index == audioindex)
+        {
+
+            ret = avcodec_decode_audio4(aCodecCtx, aFrame, &got_frame, packet);
+//            qDebug()<<ret<<got_frame;
+            if(ret < 0)
+            {
+                fprintf(stderr,"video Audio Error.\n");
+//                return;
+            }
+
+            if (got_frame)
+            {
+//                int data_size = aFrame->linesize[0];
+
+                int framSize = av_samples_get_buffer_size(NULL,aCodecCtx->channels, aFrame->nb_samples,aCodecCtx->sample_fmt, 1);
+
+                uint8_t * audio_buf = (uint8_t *)malloc(framSize);
+                memcpy(audio_buf, aFrame->data[0], framSize);
+                mAACEncoder->inputPcmBuffer((uint8_t*)audio_buf,framSize);
+
+                fwrite(audio_buf,1,framSize,pcmFp);
+            }
+        }
+        else
+        {
+            qDebug()<<"other"<<packet->stream_index;
+        }
+        av_free_packet(packet);
+    }
+
+    qDebug()<<"record stopping...";
+
+    m_pause = false;
+
+    deInit();
+
+    qDebug()<<"record finished!";
+
+}
+

+ 75 - 0
src/audio/getaudiothread.h

@@ -0,0 +1,75 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef GetAudioThread_H
+#define GetAudioThread_H
+
+#include <QThread>
+
+extern "C"
+{
+#include "libavcodec/avcodec.h"
+#include "libavformat/avformat.h"
+#include "libswscale/swscale.h"
+#include "libavdevice/avdevice.h"
+}
+
+#include "AACEncoder.h"
+
+/**
+ * @brief The GetAudioThread class  此类主要负责获取录音数据 并使用ffmpeg编码成AAC
+ */
+
+enum ErroCode
+{
+    AudioOpenFailed = 0,
+    VideoOpenFailed,
+    AudioDecoderOpenFailed,
+    VideoDecoderOpenFailed,
+    SUCCEED
+};
+
+
+class GetAudioThread : public QThread
+{
+    Q_OBJECT
+
+public:
+    explicit GetAudioThread();
+    ~GetAudioThread();
+
+    /**
+     * @brief init 初始化打开录屏设备
+     * @param videoDevName
+     * @return
+     */
+    ErroCode init(QString audioDevName);
+    void deInit();
+
+    void startRecord();
+    void pauseRecord();
+    void restoreRecord();
+    void stopRecord();
+
+protected:
+    void run();
+
+private:
+    AVFormatContext	*pFormatCtx;
+    int				i, audioindex;
+    AVCodecContext	*aCodecCtx;
+
+    AVFrame	*aFrame;
+    uint8_t *out_buffer;
+
+    bool m_isRun;
+    bool m_pause;
+
+    AACEncoder *mAACEncoder;
+
+};
+
+#endif // GetAudioThread_H

+ 28 - 0
src/main.cpp

@@ -0,0 +1,28 @@
+
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include <QApplication>
+#include <QTextCodec>
+
+#include "mainwindow.h"
+
+#undef main
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+
+    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+    QTextCodec::setCodecForLocale(codec);
+    QTextCodec::setCodecForCStrings(codec);
+    QTextCodec::setCodecForTr(codec);
+
+    MainWindow w;
+    w.show();
+
+    return a.exec();
+}
+

+ 92 - 0
src/mainwindow.cpp

@@ -0,0 +1,92 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include <QMessageBox>
+
+MainWindow::MainWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainWindow)
+{
+    ui->setupUi(this);
+
+    av_register_all();
+    avformat_network_init();
+    avdevice_register_all();
+
+    mAudioThread = NULL;
+
+    connect(ui->pushButton_start,SIGNAL(clicked()),this,SLOT(slotBtnClicked()));
+    connect(ui->pushButton_stop,SIGNAL(clicked()),this,SLOT(slotBtnClicked()));
+
+    ui->pushButton_start->setEnabled(true);
+    ui->pushButton_stop->setEnabled(false);
+
+}
+
+MainWindow::~MainWindow()
+{
+    delete ui;
+}
+
+bool MainWindow::startRecord()
+{
+    bool isSucceed = false;
+do
+{
+    if (mAudioThread != NULL)
+        delete mAudioThread;
+
+    mAudioThread = new GetAudioThread;
+
+    /// 使用ffmepg命令行获取录音设备 然后拷贝进来:
+    /// ffmpeg -list_devices true -f dshow -i dummy  2>E:/out.txt
+    /// 打开E:\out.txt即可看到设备
+    if (mAudioThread->init("插孔麦克风 (Realtek Audio)") == SUCCEED)
+    {
+        mAudioThread->startRecord();
+    }
+    else
+    {
+        QMessageBox::critical(NULL,"提示","出错了,初始化录屏设备失败!");
+
+        break;
+    }
+
+    ui->pushButton_start->setEnabled(false);
+    ui->pushButton_stop->setEnabled(true);
+
+    isSucceed = true;
+
+    ui->pushButton_start->setEnabled(false);
+    ui->pushButton_stop->setEnabled(true);
+
+}while(0);
+
+    return isSucceed;
+}
+
+void MainWindow::stopRecord()
+{
+    if (mAudioThread != NULL)
+        mAudioThread->stopRecord();
+    ui->pushButton_start->setEnabled(true);
+    ui->pushButton_stop->setEnabled(false);
+}
+
+void MainWindow::slotBtnClicked()
+{
+    if (QObject::sender() == ui->pushButton_start)
+    {
+        startRecord();
+    }
+    else if (QObject::sender() == ui->pushButton_stop)
+    {
+        stopRecord();
+    }
+}

+ 42 - 0
src/mainwindow.h

@@ -0,0 +1,42 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+#include "audio/getaudiothread.h"
+
+namespace Ui {
+class MainWindow;
+}
+
+/**
+ * @brief The MainWindow class 界面操作相关的主窗体类
+ */
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    explicit MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+private:
+    Ui::MainWindow *ui;
+
+    GetAudioThread *mAudioThread; //采集麦克风的线程
+
+    bool startRecord();
+    void stopRecord();
+
+private slots:
+    void slotBtnClicked();
+};
+
+#endif // MAINWINDOW_H

+ 67 - 0
src/mainwindow.ui

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>454</width>
+    <height>418</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <widget class="QPushButton" name="pushButton_start">
+    <property name="geometry">
+     <rect>
+      <x>60</x>
+      <y>180</y>
+      <width>91</width>
+      <height>41</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>开始采集</string>
+    </property>
+   </widget>
+   <widget class="QPushButton" name="pushButton_stop">
+    <property name="geometry">
+     <rect>
+      <x>200</x>
+      <y>180</y>
+      <width>91</width>
+      <height>41</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>停止采集</string>
+    </property>
+   </widget>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>454</width>
+     <height>23</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="mainToolBar">
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 2 - 2
说明.txt

@@ -1,4 +1,4 @@
-从零开始学习音视频编程技术(十三) 录屏软件开发之屏幕录像
+从零开始学习音视频编程技术(十八) 录屏软件开发之编码AAC
 
 
 这是Qt的工程,建议使用Qt Creator 打开
@@ -12,7 +12,7 @@ FFMPEG
 
 
 关于代码的解释 请参考:
-http://blog.yundiantech.com/?log=blog&id=16
+http://blog.yundiantech.com/?log=blog&id=24
 
 
 Qt开发环境的搭建 请参考: