ffmpeg 摄像头,麦克风采集,编码成h264,aac

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //ffmpeg初始化
    av_register_all();
    avformat_network_init();
    avdevice_register_all();


    out_buffer = NULL;
    pFrame = NULL;
    pFrameYUV = NULL;
    pCodecCtx = NULL;

//编码用到的
AVCodecContext* pCodecCtx1;
AVCodec* pCodec1;
pCodecCtx1 = NULL;
pCodec1 = NULL;
 //   AVFormatContext *pFormatCtx = avformat_alloc_context();
 //   AVInputFormat *ifmt=av_find_input_format("dshow");

 //     XiaoMi USB 2.0 Webcam
 //   avformat_open_input(&pFormatCtx,"video=e2eSoft VCam",ifmt,NULL) ;

    AVCodec			*pCodec = NULL;

    打开摄像头设备
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    AVDictionary* options = NULL;
  //  av_dict_set(&options,"list_devices","true",0);//显示可用的dshow设备

    AVInputFormat *iformat = av_find_input_format("dshow");

    if( avformat_open_input(&pFormatCtx,"video=XiaoMi USB 2.0 Webcam",iformat,NULL) != 0)//dummy
    {

        qDebug()<<"Couldn't open input stream video.(无法打开输入流)\n";
    }

    打开麦克风设备
    QString audioDevName("麦克风 (Realtek High Definition Audio)");
    QString audioDevOption = QString("audio=%1").arg(audioDevName);
    if( avformat_open_input(&pFormatCtx,audioDevOption.toUtf8(),iformat,NULL) != 0)//dummy
    {

        qDebug()<<"Couldn't open input stream video.(无法打开麦克风)\n";
    }

    if(avformat_find_stream_info(pFormatCtx,NULL)<0)
    {
            qDebug()<<"Couldn't find stream information.";
            return ;
    }

    //视频解码
    videoindex =-1;
    pCodecCtx = NULL;

    for(i=0; i<pFormatCtx->nb_streams; i++)
    {
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
        {
            videoindex=i;
            break;
        }
    }

    if(videoindex==-1)
    {
        qDebug()<<"Didn't find a video stream.(没有找到视频流)";
        return ;
    }

    pCodecCtx = pFormatCtx->streams[videoindex]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);

    if(pCodec==NULL)
    {
        qDebug()<<"Codec not found.";
        return ;
    }

    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
    {
        qDebug()<<"Could not open codec.";
        return ;
    }
    pFrame=avcodec_alloc_frame();
    pFrameYUV=avcodec_alloc_frame();
    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);


    
    /// \brief ret
    ///

    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)
    {
        qDebug()<<"Didn't find a video stream.(没有找到音频流)";
        return;
    }

    aCodecCtx = pFormatCtx->streams[audioindex]->codec;

    aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
    if(aCodec == NULL)
    {
        qDebug()<<"audio Codec not found.";
        return;
    }

    if(avcodec_open2(aCodecCtx, aCodec,NULL)<0)
    {
        qDebug()<<"Could not open video codec.";
        return;
    }
    aFrame=avcodec_alloc_frame();




    int ret, got_frame;
    struct SwsContext *img_convert_ctx = NULL;

    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    //读取frame
    AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));







    const QString tfileName = "JJJ.yuv";
    const QString tfileName2 = "JJJ.h264";
    const QString tfileName3 = "jjj.pcm";
    const QString tfileName4 = "jjj.aac";
    QFile tmpfile,tmpfile2,tmpfile3,tmpfile4;
    tmpfile.setFileName(tfileName);
    tmpfile2.setFileName(tfileName2);
    tmpfile3.setFileName(tfileName3);
    tmpfile4.setFileName(tfileName4);

    tmpfile.open(QIODevice::WriteOnly);
    if (!tmpfile.isOpen())
    {
        qDebug() << "file is not open";return;
    }
    if (!tmpfile.isWritable())
    {
        qDebug() << "file  write disable";
        return;
    }
    tmpfile2.open(QIODevice::WriteOnly);
    tmpfile3.open(QIODevice::WriteOnly);
    tmpfile4.open(QIODevice::WriteOnly);

    //编码相关
    AVPacket pkt;
    av_new_packet(&pkt,640*480*3);
    AVPacket pkt1;
    av_new_packet(&pkt1,4096);
    int size;
    int in_w = 640;
    int in_h = 480;//宽高

    //查找并打开h264编码器
   pCodec1 = avcodec_find_encoder(AV_CODEC_ID_H264);
    if(!pCodec1)
    {
      qDebug()<<"h264 codec not found";

    }

    pCodecCtx1 = avcodec_alloc_context3(pCodec1);

    pCodecCtx1->codec_id = AV_CODEC_ID_H264;
    pCodecCtx1->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx1->pix_fmt = PIX_FMT_YUV420P;
    pCodecCtx1->width = in_w;
    pCodecCtx1->height = in_h;
    pCodecCtx1->time_base.num = 1;
    pCodecCtx1->time_base.den = 15;//帧率(既一秒钟多少张图片)
    pCodecCtx1->bit_rate = 600000; //比特率(调节这个大小可以改变编码后视频的质量)
    pCodecCtx1->gop_size=12;

    // some formats want stream headers to be separate
    if (pCodecCtx1->flags & AVFMT_GLOBALHEADER)
        pCodecCtx1->flags |= CODEC_FLAG_GLOBAL_HEADER;

    // Set Option
    AVDictionary *param = 0;
    //H.264
    //av_dict_set(&param, "preset", "slow", 0);
    av_dict_set(&param, "preset", "superfast", 0);
    av_dict_set(&param, "tune", "zerolatency", 0);  //实现实时编码


    //pCodec1 = avcodec_find_encoder(pCodecCtx1->codec_id);
 //   if (!pCodec1){
  //    qDebug()<<"Can not find video encoder! 没有找到合适的编码器!";
  //    return ;
  //  }

    if (avcodec_open2(pCodecCtx1, pCodec1,&param) < 0){
      qDebug()<<"Failed to open video encoder! 编码器打开失败!";
      return ;
    }


    //查找并打开AAC编码器

    AVCodecContext* pCodecCtx2;    AVCodec* aCodec1;
    AVFrame* frame;

    int ONEFrameSize = 0; //一帧长度传入ffmpeg的
    int mAacBufferIndex = 0;
    int mAacBufferSize = 0;
    //这段代码必须放到前面
    aCodec1 = avcodec_find_encoder(AV_CODEC_ID_AAC);//pCodecCtx2->codec_id
    if (!aCodec1)
    {
        qDebug()<<"没有找到合适的编码器!";
        return;
    }
#if 1
    pCodecCtx2 = avcodec_alloc_context3(aCodec1);
    pCodecCtx2->codec_id = AV_CODEC_ID_AAC;
    pCodecCtx2->codec_type = AVMEDIA_TYPE_AUDIO;
    pCodecCtx2->sample_fmt = AV_SAMPLE_FMT_S16;
    pCodecCtx2->sample_rate= 44100;
    pCodecCtx2->channel_layout=AV_CH_LAYOUT_STEREO;
    pCodecCtx2->channels = av_get_channel_layout_nb_channels(pCodecCtx2->channel_layout);
    pCodecCtx2->bit_rate = 64000;


    if (avcodec_open2(pCodecCtx2, aCodec1,NULL) < 0)
    {
        qDebug()<<"编码器打开失败!";
        return;
    }

    //之前没有声音是因为frame没有初始化完成
    frame = avcodec_alloc_frame();//不是av_frame_alloc()
    frame->nb_samples = pCodecCtx2->frame_size;
    frame->format = pCodecCtx2->sample_fmt;
    ONEFrameSize = av_samples_get_buffer_size(NULL,pCodecCtx2->channels,pCodecCtx2->frame_size,pCodecCtx2->sample_fmt, 1);

#endif
    while(1)
    {
        if(av_read_frame(pFormatCtx, packet) < 0)
        {

             break;
        }

        if(packet->stream_index==videoindex)
        {

            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_frame, packet);
            if(ret < 0)
            {
                qDebug()<<"video Decode Error.(解码错误)";
                return;
            }
            if(got_frame && pCodecCtx)
            {
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

                //将yuv420p的图像写入文件
                int y_size = pCodecCtx->width*pCodecCtx->height;
                //   640 480
               // qDebug()<<y_size << pCodecCtx->width << pCodecCtx->height;

                //保存成yuv格式文件 注释掉
              //  tmpfile.write((const char*)pFrameYUV->data[0],y_size);
              //  tmpfile.write((const char*)pFrameYUV->data[1],y_size/4);
              //  tmpfile.write((const char*)pFrameYUV->data[2],y_size/4);


                //编码成h264


                // picture->data[0] = node.buffer;     // 亮度Y
                // picture->data[1] = node.buffer + y_size;  // U
                // picture->data[2] = node.buffer + y_size*5/4; // V

                 int got_picture=0;
                 //编码
                 int ret = avcodec_encode_video2(pCodecCtx1, &pkt,pFrameYUV, &got_picture);
                 if (got_picture==1)
                 {

                 //   bool isKeyFrame = pkt.flags & AV_PKT_FLAG_KEY; //判断是否关键帧
                      //int w = fwrite(pkt.data,1,pkt.size,h264Fp); //写入文件中 (h264的裸数据 直接写入文件 也可以播放  因为这里包含H264关键帧)
                    tmpfile2.write((const char*)pkt.data,pkt.size);
                 }
                av_free_packet(&pkt);
            }


        }
        else if(packet->stream_index==audioindex)
        {
            //解码音频帧
            ///这里打印出音频的信息
            //qDebug()<<"audio info:"<<aCodecCtx->sample_fmt<<aCodecCtx->bit_rate<<aCodecCtx->sample_rate<<aCodecCtx->channels;

            //解码声音数据成PCM数据
            ret = avcodec_decode_audio4(aCodecCtx, aFrame, &got_frame, packet);
            if(ret < 0)
            {
                return;
            }

            if (got_frame&&aCodecCtx)
            {
                int pcmSize = av_samples_get_buffer_size(NULL,aCodecCtx->channels, aFrame->nb_samples,aCodecCtx->sample_fmt, 1);
                uint8_t * pcmBuffer = aFrame->data[0];

                float useTime = aFrame->nb_samples * 1.0 / aCodecCtx->sample_rate;
                //Time += useTime;
                //qDebug()<<useTime;//<<i<<Time
                //fwrite(pcmBuffer,1,pcmSize,fp_pcm);
                写入文件

                //tmpfile3.write((const char*)pcmBuffer,pcmSize);

                //编码成AAC
                //每次传递给编码器的数据大小必须要是上数的"ONEFrameSize"
                //因此有了下面的while循环
#if 1
                while(1)
                {
                    int size=pcmSize-mAacBufferIndex;
                    if(size < ONEFrameSize)
                    {
                        memcpy(pcmBuffer,pcmBuffer+mAacBufferIndex,size);
                        mAacBufferIndex = 0;
                        pcmSize = size;
                        break;

                    }
                    frame->data[0] = pcmBuffer+mAacBufferIndex;
                    mAacBufferIndex += ONEFrameSize;

                   int got_frame1=0;

                    //编码

                    ret  = avcodec_encode_audio2(pCodecCtx2, &pkt1,frame, &got_frame1);

                    if(ret < 0)
                    {
                         qDebug()<<"avcodec_encode_audio2"<<ret;
                    }
                    if (got_frame1==1)
                    {
                        /// 编码后的数据是带ADTS头的 因此写入文件后 可以直接用播放器播放
                        //fwrite(pkt.data,1,pkt.size,aacFp);

                        tmpfile4.write((const char*)pkt1.data,pkt1.size);
                        av_free_packet(&pkt1);
                    }
                }
#endif
            }


        }
        av_free_packet(packet);
    }


}

用的是ffmpeg2.5  仅用于测试

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
敬告:该系列的课程在抓紧录制更新中,敬请大家关注。敬告: 该系列的课程涉及:FFmpeg,WebRTC,SRS,Nginx,Darwin,Live555,等。包括:音视频、流媒体、直播、Android、视频监控28181、等。  我将带领大家一起来学习:采集麦克风、PCM重采样、AAC或MP3音频编码存储、并直播。具体内容包括:1.FFmpeg采集麦克风并存储为PCM。2.PCM重采样原理及实战。3.采集麦克风并实时转码AAC或MP3并保存文件。4.采集麦克风并实时转码AAC并可以直播。 音视频与流媒体是一门很复杂的技术,涉及的概念、原理、理论非常多,很多初学者不学 基础理论,而是直接做项目,往往会看到c/c++的代码时一头雾水,不知道代码到底是什么意思,这是为什么呢? 因为没有学习音视频和流媒体的基础理论,就比如学习英语,不学习基本单词,而是天天听英语新闻,总也听不懂。所以呢,一定要认真学习基础理论,然后再学习播放器、转码器、非编、流媒体直播、视频监控、等等。 梅老师从事音视频与流媒体行业18年;曾在永新视博、中科大洋、百度、美国Harris广播事业部等公司就职,经验丰富;曾亲手主导广电直播全套项目,精通h.264/h.265/aac,曾亲自参与百度app上的网页播放器等实战产品。 目前全身心自主创业,主要聚焦音视频+流媒体行业,精通音视频加密、流媒体在线转码快编等热门产品。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gws09876

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值