音视频学习笔记 01 打开音频设备

141 阅读4分钟

ffmpeg.org/download.ht… 下载源码

编译 ffmpeg

# ./configure -h 如果参数忘了可以通过这条命令查看
./configure --prefix=/Users/mac/ffmpeg-7.1.1 --disable-static --enable-shared --enable-debug=3

make -j 4

make install

如果编译时不禁用静态库,并且开启共享库,连接编译时会收获 101 个 undefined symbol 编译错误,如果上面照做了则不会,

'/Users/mac/ffmpeg-7.1.1/lib/libavutil.59.39.100.dylib' not valid for use in process: mapped file has no cdhash, completely unsigned? Code has to be at least ad-hoc signed

这个是动态链接库签名错误。下面答案来自 deepseek。

==== 这个错误表明你的 FFmpeg 动态库(.dylib)  没有被正确签名,而 macOS(特别是较新版本如 macOS 10.15+)要求所有可执行文件和动态库必须经过 代码签名,即使是本地运行也需要 ad-hoc 签名(最低级别的签名)。


解决方法

1. 使用 codesign 进行 ad-hoc 签名

codesign -f -s - /Users/mac/ffmpeg-7.1.1/lib/libavutil.59.39.100.dylib
  • -f:强制覆盖现有签名
  • -s -:使用 ad-hoc 签名(不依赖开发者证书)
  • 最后指定 .dylib 文件路径

对所有 FFmpeg 动态库签名:

for lib in /Users/mac/ffmpeg-7.1.1/lib/*.dylib; do
    codesign -f -s - "$lib"
done

2. 如果仍然报错:检查 SIP 和文件权限

  • 确保 SIP(系统完整性保护)未阻止签名(默认开启,一般无需关闭)。

  • 确保你有文件读写权限

    chmod +x /Users/mac/ffmpeg-7.1.1/lib/libavutil.59.39.100.dylib
    

3. 如果使用 Xcode 运行

  • 在 Xcode 项目的 Build Phases 里添加 Run Script,自动签名动态库:

    find "$CODESIGNING_FOLDER_PATH" -name "*.dylib" -exec codesign -f -s - {} ;
    

4. 其他可能的问题

  • 动态库路径错误:检查 .dylib 是否在正确位置。

  • FFmpeg 版本兼容性:尝试重新编译 FFmpeg(--enable-shared 确保生成正确的动态库)。

  • macOS 安全策略:如果仍然报错,尝试在终端运行:

    sudo spctl --master-disable  # 临时禁用 Gatekeeper(不推荐长期使用)
    

总结

  • 必须签名:macOS 要求所有 .dylib 文件至少要有 ad-hoc 签名
  • 推荐方法:使用 codesign -f -s - 签名所有 FFmpeg 动态库。
  • Xcode 集成:通过 Run Script 自动签名,避免手动操作。

如果问题仍然存在,可能是动态库损坏或编译问题,建议重新编译 FFmpeg 或检查依赖项。

====

This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data

image.png

image.png

image.png

1 设置 ffmpeg 动态库

image.png

2 设置沙盒

image.png

3 设置头文件搜索路径

image.png

创建 testc.c 文件

image.png

image.png

勾选 创建头文件

image.png

点击创建

image.png

第一次创建 c 语言文件会提示 是否创建桥接文件,点击创建

image.png

代码:

桥接文件

// myapp-Bridging-Header.h

#import "testc.h"

c 代码 文件头

// testc.h 头文件
#ifndef testc_h

#define testc_h

#include <stdio.h>

#include "libavutil/avutil.h"

#include "libavdevice/avdevice.h"

#include "libavformat/avformat.h"

void haha(void);

#endif /* testc_h */

其中下面的代码中 devicename 的值

// [[video device]:[audio device]] 
char *devicename = ":2";

可以通过 下面的方式获取

➜  bin ./ffmpeg -f avfoundation -list_devices true -i ' '
ffmpeg version 7.1.1 Copyright (c) 2000-2025 the FFmpeg developers
  built with Apple clang version 17.0.0 (clang-1700.0.13.5)
  configuration: --prefix=/Users/mac/ffmpeg-7.1.1 --disable-static --enable-shared --enable-debug=3
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
2025-06-26 22:10:51.377 ffmpeg[2000:14415] WARNING: Add NSCameraUseContinuityCameraDeviceType to your Info.plist to use AVCaptureDeviceTypeContinuityCamera.
[AVFoundation indev @ 0x7fcbc7904ac0] AVFoundation video devices:
[AVFoundation indev @ 0x7fcbc7904ac0] [0] FaceTime HD Camera (Built-in)
[AVFoundation indev @ 0x7fcbc7904ac0] [1] OBS Virtual Camera
[AVFoundation indev @ 0x7fcbc7904ac0] [2] Capture screen 0
[AVFoundation indev @ 0x7fcbc7904ac0] AVFoundation audio devices:
[AVFoundation indev @ 0x7fcbc7904ac0] [0] MacBook Pro Microphone
[in#0 @ 0x7fcbc7904400] Error opening input: Input/output error
Error opening input file  .
Error opening input files: Input/output error

c 代码文件体

// testc.c 文件体

//
//  testc.c
//  myapp
//
//  Created by mac on 2025/6/23.
//
#include "testc.h"

void haha(void) {
    int ret = 0;
    char errors[1024];
    
    AVFormatContext *fmt_ctx = NULL;
    
    AVDictionary *options = NULL;
    
    // [[video device]:[audio device]]
    char *devicename = ":2";
    
    
    // 1 register audio device
    avdevice_register_all();
                
    // 2 get format
    // const AVInputFormat *iformat = av_find_input_format("avfoundation");
    const AVInputFormat *i_format = av_find_input_format("avfoundation");
    
    // 3 open device
    ret = avformat_open_input(&fmt_ctx, devicename, i_format, &options);
    
    if (ret < 0) {
        av_strerror(ret, errors, 1024);
        printf(stderr, "Failed to open audio device [%d] %s\n", ret, errors);
        
        return;
    }
    printf("this is a c function\n");
    
    av_log_set_level(AV_LOG_DEBUG);
    
    av_log(NULL, AV_LOG_DEBUG, "hello world from av_log \n ");
    
    return;
}

// ViewController.swift

//
//  ViewController.swift
//  myapp
//
//  Created by mac on 2025/6/23.
//

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.setFrameSize(NSSize(width: 320, height: 240))
        let btn = NSButton.init(title: "Button", target: nil, action: nil)
        btn.title = "Hello"
        btn.frame = NSRect(x: 320 / 2 - 40, y: 240 / 2 - 15, width: 80, height: 30)
        btn.bezelStyle = .rounded
        btn.setButtonType(.pushOnPushOff)
        
        // callback
        btn.target = self
        btn.action = #selector(myFunc)
        
        self.view.addSubview(btn)
        // Do any additional setup after loading the view.
    }
    
    @objc
    func myFunc(){
        // print("Hello World")
        haha()
    }

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

}