swift语法
//
// main.swift
// first_swift
//
// Created by lichao on 2020/1/29.
// Copyright © 2020年 lichao. All rights reserved.
//
import Foundation
/*
swift语言的特点:没有main函数,入口是main.swift
1. var 变量 let 常量
var a = 10
var b:Int =20
2. 可以不写分号
3. switch 没有break关键字,case执行后结束 不会连在一起
4 循环 for while for in list
5 函数 func
*/
let a = 555
var b = 456
if a < 500 {
print("the a is less than 500")
}else {
print("the a is more than 500")
}
switch a {
case 123:
print("the value is 123")
case 456:
print("the value is 456")
default:
print("the value is ", a)
}
var list = [1,2,3,4,5,6]
for i in list {
print(i)
}
// 连续数组 0-100
for i in 0..<100 {
print("for==", i)
}
var loop = 0
while loop < 100 {
print("loop=", loop)
loop = loop + 1
}
func myfunc(a : Int)->Int{
var b: Int = 0
b = a + 10
return b
}
var aa = 20
print("Hello, World!", a, b, myfunc(a: aa))
创建Mac App
随后点击创建,选择保存项目的路径即可。产生的文件:
AppDelegate.swift 一般不做逻辑操作
ViewController.swift 做主要的工作 在viewDidLoad中做窗口的初始化
Assets.xcassets 资源 如AppIcon
Main.storyboard 可以使用拖拽方式实现布局
Info.plist 项目基本信息
打开一个窗口
窗口与view的关系:窗口并不是显示在屏幕上的窗口,是描述的信息(title 大小 最小化最大化等),并不会真正的显示出来;view将窗口显示出来:将窗口的信息交给view,view根据信息显示出来窗口
设置View大小:self.view.setFrameSize (self 代表this)
显示控件:self.view.addSubView
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//设置窗口大小
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:100,y:100,width: 80,height: 50);//显示位置 mac app 原点在左下角不是在左上角
btn.setButtonType(.pushOnPushOff);
//设置控件回调函数callback func:注意:回调函数前要加 @objc
btn.target = self;
btn.action = #selector(myfunc);
//添加子控件
self.view.addSubview(btn);
}
@objc
func myfunc(){
print("hello world");
testc_show();
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
Swift调用C函数
ffmepg 是用C语言实现的。
1.编写C函数
2. 在桥接头文件中引入C头文件
3. 在swift中直接调用C函数
next 在弹出的对话框中选择create Bridging Header 即创建桥接头文件
创建出的三个文件:
在桥接头文件中引入c的头文件,即可使用c文件中定义的接口
如定义以下接口:
使用接口:
引入ffmpeg
ffmpeg在mac下安装:
brew方式安装:
源码方式安装(选择):
1.下载源码:
git clone https://git.ffmpeg.org/ffmpeg.git
2.编译
首先进入代码文件夹:执行
./configure --prefix=/Users/jiweili/Project/ffmpeg/mac_build --enable-debug=3 --enable-static --enable-nonfree --enable-libmp3lame --disable-shared
其中:
--prefix=/Users/jiweili/Project/ffmpeg/mac_build 是安装位置
--enable-debug=3 调试级别 方便调试代码
--enable-static 生成静态库
--disable-shared 不生成动态库
--enable-nonfree --enable-libmp3lame 生成mp3编码库
然后执行: -j 指定并发编译的cpu个数
make -j 4
最后
make install
添加ffmpeg
需要将ffmpeg静态库需要的其他库页添加,否则必报错。
关闭沙箱:
打开音频设备
int open_device(){
AVFormatContext* fmt_ctx=NULL;
int ret;
char errors[1024];
//[[video device]:[audio device]] : 代表可以选
char devicename[] = ":0";//第一个音频设备
//1 注册设备
avdevice_register_all();
//2 获取格式
AVInputFormat * input_format = av_find_input_format("avfoundation");
if (NULL == input_format)
{
printf("av_find_input_format fail\n");
return -1;
}
//打开设备 url可以是本地地址或网络地址
ret = avformat_open_input(&fmt_ctx, devicename,input_format, NULL);
if (ret)
{
av_strerror(ret, errors, 1024);
printf("avformat_open_input fail,[%d]%s",ret,errors);
return -1;
}
return 0;
}
从音频设备中读取音频数据
/**
* Return the next frame of a stream.
* This function returns what is stored in the file, and does not validate
* that what is there are valid frames for the decoder. It will split what is
* stored in the file into frames and return one for each call. It will not
* omit invalid data between valid frames so as to give the decoder the maximum
* information possible for decoding.
*
* If pkt->buf is NULL, then the packet is valid until the next
* av_read_frame() or until avformat_close_input(). Otherwise the packet
* is valid indefinitely. In both cases the packet must be freed with
* av_packet_unref when it is no longer needed. For video, the packet contains
* exactly one frame. For audio, it contains an integer number of frames if each
* frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames
* have a variable size (e.g. MPEG audio), then it contains one frame.
*
* pkt->pts, pkt->dts and pkt->duration are always set to correct
* values in AVStream.time_base units (and guessed if the format cannot
* provide them). pkt->pts can be AV_NOPTS_VALUE if the video format
* has B-frames, so it is better to rely on pkt->dts if you do not
* decompress the payload.
*
* @return 0 if OK, < 0 on error or end of file
*/
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
/**
* Initialize optional fields of a packet with default values.
*
* Note, this does not touch the data and size members, which have to be
* initialized separately.
*
* @param pkt packet
*/
void av_init_packet(AVPacket *pkt);
/**
* Wipe the packet.
*
* Unreference the buffer referenced by the packet and reset the
* remaining packet fields to their default values.
*
* @param pkt The packet to be unreferenced.
*/
void av_packet_unref(AVPacket *pkt);
/**
* Allocate an AVPacket and set its fields to default values. The resulting
* struct must be freed using av_packet_free().
*
* @return An AVPacket filled with default values or NULL on failure.
*
* @note this only allocates the AVPacket itself, not the data buffers. Those
* must be allocated through other means such as av_new_packet.
*
* @see av_new_packet
*/
AVPacket *av_packet_alloc(void);
/**
* Free the packet, if the packet is reference counted, it will be
* unreferenced first.
*
* @param pkt packet to be freed. The pointer will be set to NULL.
* @note passing NULL is a no-op.
*/
void av_packet_free(AVPacket **pkt);
对于av_packet_alloc 做了两个操作,首先分配一个AVPacket的内存,然后调用av_init_packet对这块内存初始化
AVPacket *av_packet_alloc(void)
{
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
if (!pkt)
return pkt;
av_packet_unref(pkt);
return pkt;
}
void av_packet_unref(AVPacket *pkt)
{
av_packet_free_side_data(pkt);
av_buffer_unref(&pkt->buf);
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
}
void av_init_packet(AVPacket *pkt)
{
pkt->pts = AV_NOPTS_VALUE;
pkt->dts = AV_NOPTS_VALUE;
pkt->pos = -1;
pkt->duration = 0;
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
pkt->convergence_duration = 0;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->flags = 0;
pkt->stream_index = 0;
pkt->buf = NULL;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
}
void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return;
av_packet_unref(*pkt);
av_freep(pkt);
}
录制音频
./ffplay -ar 44100 -ac 2 -f f32le /Users/jiweili/Desktop/macapp/macapp/audio.pcm 播发音频
通过界面控制录制
git仓库:
git@github.com:Paul199406/rec_recording.git