JoJo的个人博客

记录精彩的程序人生

目录
音视频系统入门3之实战音频采集
/    

音视频系统入门3之实战音频采集

Xcode新建一个mac app项目,实现录制声音的功能

引入ffmpeg库

  • 将ffmpeg库文件及头文件拷贝到目录中

    mkdir libs
    mkdir include
    cp -r /usr/local/ffmpeg/lib/* ./libs  
    cp -r /usr/local/ffmpeg/include/* ./include
  • 引入库文件和头文件

    Xcode -> General -> Frameworks,Libraries下添加libs。选择libavdevice.dyliblibavformat.dyliblibavutil.dylib

    BuidSettings -> Search Paths ->User Header Search Paths下debug和release都添加路径

    /Users/****(项目路径)/include

  • 关闭沙箱

    关闭App Sandbox

添加micro权限

info.list文件添加Microphone Usage Description权限

代码

ViewContriller.swift

import Cocoa

class ViewControllerNSViewController {

    var recStatus: Bool = false;
    let btn = NSButton.init(title: "", target: self, action: #selector(myFunc))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.setFrameSize(NSSize(width: 320, height: 240))
        btn.title = "开始录制"
        btn.frame = NSRect(x: 320/2-60, y: 240/2-15, width: 120, height: 30)
        btn.bezelStyle = .rounded
        btn.setButtonType(.pushOnPushOff)
        self.view.addSubview(btn)
        
    }
    
    @objc func myFunc() {
        recStatus = !recStatus;
        if recStatus {
            let thread: Thread? = Thread.init(target: self, selector: #selector(self.recAudio), object: nil)
            thread?.start()
            self.btn.title = "停止录制"
        } else {
            set_status(0);
            self.btn.title = "开始录制"
        }
    }
    
    @objc func recAudio() {
        record_audio();
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

test.h

#ifndef test_h
#define test_h

#include <stdio.h>
#include <unistd.h>
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"

void set_status(int status);
void record_audio(void);

#endif /* test_h */

test.c

#include "test.h"

static int rec_status = 0;

void set_status(int status) {
    rec_status = status;
}

void record_audio() {
    
    int ret = 0;
    char errors[1024] = {0, };
    
    //ctx 设置上下文
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;
    
    //packet
    AVPacket pkt;
    int count = 0;
    
    //[[video device]:[audio device]]
    char *devicename = ":0";
    
    //set log level
    av_log_set_level(AV_LOG_DEBUG);
    
    //start record 开始录制
    rec_status = 1;
    
    //register audio device
    avdevice_register_all();
    
    //get format 采集格式
    AVInputFormat *iformat = av_find_input_format("avfoundation");
    
    //open device 打开设备
    if ((ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options)) < 0) {
        av_strerror(ret, errors, 1024);
        av_log(NULL, AV_LOG_INFO,"Failed to open audio device, [%d]%s\n", ret, errors);
        return;
    }
    
    av_init_packet(&pkt);
    
    //create file
    char *out = "/Users/tianyang/Desktop/av_base/audio.pcm";
    FILE *outfile = fopen(out, "wb+");
    
    
    //read data from device 读取数据
    while (1) {
        ret = av_read_frame(fmt_ctx, &pkt);
        if (ret == -35) {
            usleep(100);
            continue;
        }
        if (ret != 0 || rec_status != 1) {
            break;
        }
        av_log(NULL, AV_LOG_INFO, "pkt size is %d(%p), count=%d \n",
               pkt.size, pkt.data, count);

        //write file
        fwrite(pkt.data, pkt.size, 1, outfile);
        fflush(outfile);
        
        
        //release packet 释放packet
        av_packet_unref(&pkt);
    }
    
  
    av_log(NULL, AV_LOG_DEBUG, "finish!\n");
    
    //close file
    fclose(outfile);
    
    //close device and release ctx
    avformat_close_input(&fmt_ctx);
    
    return;
}

av_read_frame出现返回-35的情况,进行usleep(100);睡眠一段时间处理

播放输出文件

ffplay -ar 44100 -ac 2 -f f32le audio.pcm

代码仓

FFmpegProject


标题:音视频系统入门3之实战音频采集
作者:SunnySky
地址:https://www.tianyang.pub/articles/2020/11/17/1605609444383.html

评论