作者:罗源凯

ffmpeg

是一个跨平台的多媒体框架
windows,macOS下载
https://ffmpeg.zeranoe.com/builds/
linux
http://ffmpeg.org/releases/
查看文件信息工具
mediaInfo

tar -jxvf ffmpeg-3.4.1.tar.bz2
cd ffmpeg-3.4.1
安装yasm ----yum install yasm
./configure --enabled-shared --prefix=/usr/local/ffmpeg
安装:make && make install
修改文件/etc/ld.so.conf 中增加/usr/local/ffmpeg/lib.
        使其生效:ldconfig
加入环境变量:vi /etc/profile
        最后一行:export FFMPEG_HOME=/usr/local/ffmpeg
export PATH=$FFMPEG_HOME/bin:$PATH
        使环境变量生效:source /etc/profile

源码下载
git clone https://git.ffmpeg.org/ffmpeg.git
按需配制模块
./configure –help | more
安装yasm的汇编编译器
yasm:http://yasm.tortall.net/Download.html
sudo apt-get install yasm

Mac 平台:

./configure –prefix=/usr/local/ffmpeg
–enable-gpl
–enable-nonfree
–enable-libfdk-aac
–enable-libx264
–enable-libx265
–enable-filter=delogo
–enable-debug
–disable-optimizations
–enable-libspeex
–enable-videotoolbox
–enable-shared
–enable-pthreads
–enable-version3
–enable-hardcoded-tables
–cc=clang
–host-cflags=
–host-ldflags=
Linux平台
./configure –prefix=/usr/local/ffmpeg \
–enable-gpl \
–enable-nonfree \
–enable-libfdk-aac \
–enable-libx264 \
–enable-libx265 \
–enable-filter=delogo \
–enable-debug \
–disable-optimizations \
–enable-libspeex \
–enable-shared \
–enable-pthreads

Windows平台

./configure –prefix=/usr/local/ffmpeg
–enable-gpl
–enable-nonfree
–enable-libfdk-aac
–enable-libx264
–enable-libx265
–enable-filter=delogo
–enable-debug
–disable-optimizations
–enable-libspeex
–enable-static

编译安装
sudo make && make install
执行
/usr/local/ffmpeg/bin/ffmpeg
为方便执行可加入环境变量~/.bash_profile
export PATH=$PATH:/usr/local/ffmpeg/bin

可能遇到的问题
ffmpeg默认安装目录为“/usr/local/lib”,有些64位系统下软件目录则为“/usr/lib64”,编译过程中可能会出现“ffmpeg: error while loading shared libraries: libmp3lame.so.0: cannot open shared object file: No such file or directory”等类似的错误,解决办法是建立软链接或者移动库文件到相应的目录:
ln -s /usr/local/lib/libmp3lame.so.0.0.0 /usr/lib64/libmp3lame.so.0
mv /usr/local/lib/libmp3lame.so.0.0.0 /usr/lib64/libmp3lame.so.0

ERROR:libfdk_aac not found
apt install fdk-aac
http://sourceforge.net/projects/opencore-amr/?source=directory
下载fdk-aac-0.1.1.tar.gz
执行
configure
make
make install

git clone git://github.com/mstorsjo/fdk-aac
cd fdk-aac
autoreconf -i
./configure
make install

ERROR: speex not found using pkg-config
apt install pkg-config
apt-get install libspeex-dev

ERROR: libx264 not found
apt/brew/yum install x264。(注:在Linux下应该安装 libx264-dev)

ffmpeg: error while loading shared libraries: libavdevice.so.58: cannot open shared object file: No such file or directory
sudo vi /etc/ld.so.conf
在文件中添加路径:
/usr/local/ffmpeg/lib
更新环境变量:
sudo ldconfig
加入全局环境变量路径:
sudo vi /etc/profile
在文件中加入以下内容:
export PATH=”/usr/local/ffmpeg/bin:$PATH”
然后保存并运行source /etc/profile

查看下需要哪些依赖:
ldd ffmpeg
找下这些文件在哪里
find /usr -name ‘libavdevice.so.58’

FYI 《FFmpeg精讲与实战》常见问题与解答
https://www.imooc.com/article/253497

windows下安装
www.imooc.com/article/247113

基本信息查询命令

FFMPEG 可以使用下面的参数进行基本信息查询。例如,想查询一下现在使用的 FFMPEG 都支持哪些 filter,就可以用 ffmpeg -filters 来查询。详细参数说明如下:
-version 显示版本。 ffmpeg -version
-formats 显示可用的格式(包括设备)。
-demuxers 显示可用的demuxers。
-muxers 显示可用的muxers。
-devices 显示可用的设备。
-codecs 显示libavcodec已知的所有编解码器。
-decoders 显示可用的解码器。
-encoders 显示所有可用的编码器。
-bsfs 显示可用的比特流filter。
-protocols 显示可用的协议。
-filters 显示可用的libavfilter过滤器。
-pix_fmts 显示可用的像素格式。
-sample_fmts 显示可用的采样格式。
-layouts 显示channel名称和标准channel布局。
-colors 显示识别的颜色名称。

接下来介绍的是 FFMPEG 处理音视频时使用的命令格式与参数。
命令基本格式及参数

下面是 FFMPEG 的基本命令格式:

ffmpeg [global_options] {[input_file_options] -i input_url} …
{[output_file_options] output_url} …

ffmpeg 通过 -i 选项读取输任意数量的输入“文件”(可以是常规文件,管道,网络流,抓取设备等,并写入任意数量的输出“文件”。
原则上,每个输入/输出“文件”都可以包含任意数量的不同类型的视频流(视频/音频/字幕/附件/数据)。 流的数量和/或类型是由容器格式来限制。 选择从哪个输入进入到哪个输出将自动完成或使用 -map 选项。
要引用选项中的输入文件,您必须使用它们的索引(从0开始)。 例如。 第一个输入文件是0,第二个输入文件是1,等等。类似地,文件内的流被它们的索引引用。 例如。 2:3是指第三个输入文件中的第四个流。
上面就是 FFMPEG 处理音视频的常用命令,下面是一些常用参数:
主要参数

-f fmt(输入/输出) 强制输入或输出文件格式。 格式通常是自动检测输入文件,并从输出文件的文件扩展名中猜测出来,所以在大多数情况下这个选项是不需要的。
-i url(输入) 输入文件的网址
-y(全局参数) 覆盖输出文件而不询问。
-n(全局参数) 不要覆盖输出文件,如果指定的输出文件已经存在,请立即退出。
-c [:stream_specifier] codec(输入/输出,每个流) 选择一个编码器(当在输出文件之前使用)或解码器(当在输入文件之前使用时)用于一个或多个流。codec 是解码器/编码器的名称或 copy(仅输出)以指示该流不被重新编码。如:ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
-codec [:stream_specifier]编解码器(输入/输出,每个流) 同 -c
-t duration(输入/输出) 当用作输入选项(在-i之前)时,限制从输入文件读取的数据的持续时间。当用作输出选项时(在输出url之前),在持续时间到达持续时间之后停止输出。
-ss位置(输入/输出) 当用作输入选项时(在-i之前),在这个输入文件中寻找位置。 请注意,在大多数格式中,不可能精确搜索,因此ffmpeg将在位置之前寻找最近的搜索点。 当转码和-accurate_seek被启用时(默认),搜索点和位置之间的这个额外的分段将被解码和丢弃。 当进行流式复制或使用-noaccurate_seek时,它将被保留。当用作输出选项(在输出url之前)时,解码但丢弃输入,直到时间戳到达位置。
-frames [:stream_specifier] framecount(output,per-stream) 停止在帧计数帧之后写入流。
-filter [:stream_specifier] filtergraph(output,per-stream) 创建由filtergraph指定的过滤器图,并使用它来过滤流。filtergraph是应用于流的filtergraph的描述,并且必须具有相同类型的流的单个输入和单个输出。在过滤器图形中,输入与标签中的标签相关联,标签中的输出与标签相关联。有关filtergraph语法的更多信息,请参阅ffmpeg-filters手册。

视频参数

-vframes num(输出) 设置要输出的视频帧的数量。对于-frames:v,这是一个过时的别名,您应该使用它。
-r [:stream_specifier] fps(输入/输出,每个流) 设置帧率(Hz值,分数或缩写)。作为输入选项,忽略存储在文件中的任何时间戳,根据速率生成新的时间戳。这与用于-framerate选项不同(它在FFmpeg的旧版本中使用的是相同的)。如果有疑问,请使用-framerate而不是输入选项-r。作为输出选项,复制或丢弃输入帧以实现恒定输出帧频fps。
-s [:stream_specifier]大小(输入/输出,每个流) 设置窗口大小。作为输入选项,这是video_size专用选项的快捷方式,由某些分帧器识别,其帧尺寸未被存储在文件中。作为输出选项,这会将缩放视频过滤器插入到相应过滤器图形的末尾。请直接使用比例过滤器将其插入到开头或其他地方。格式是’wxh’(默认 – 与源相同)。
-aspect [:stream_specifier] 宽高比(输出,每个流) 设置方面指定的视频显示宽高比。aspect可以是浮点数字符串,也可以是num:den形式的字符串,其中num和den是宽高比的分子和分母。例如“4:3”,“16:9”,“1.3333”和“1.7777”是有效的参数值。如果与-vcodec副本一起使用,则会影响存储在容器级别的宽高比,但不会影响存储在编码帧中的宽高比(如果存在)。
-vn(输出) 禁用视频录制。
-vcodec编解码器(输出) 设置视频编解码器。这是-codec:v的别名。
-vf filtergraph(输出) 创建由filtergraph指定的过滤器图,并使用它来过滤流。
音频参数

-aframes(输出) 设置要输出的音频帧的数量。这是-frames:a的一个过时的别名。
-ar [:stream_specifier] freq(输入/输出,每个流) 设置音频采样频率。对于输出流,它默认设置为相应输入流的频率。对于输入流,此选项仅适用于音频捕获设备和原始分路器,并映射到相应的分路器选件。
-ac [:stream_specifier]通道(输入/输出,每个流) 设置音频通道的数量。对于输出流,它默认设置为输入音频通道的数量。对于输入流,此选项仅适用于音频捕获设备和原始分路器,并映射到相应的分路器选件。
-an(输出) 禁用录音。
-acodec编解码器(输入/输出) 设置音频编解码器。这是-codec的别名:a。
-sample_fmt [:stream_specifier] sample_fmt(输出,每个流) 设置音频采样格式。使用-sample_fmts获取支持的样本格式列表。
-af filtergraph(输出) 创建由filtergraph指定的过滤器图,并使用它来过滤流。
了解了这些基本信息后,接下来我们看看 FFMPEG 具体都能干些什么吧。
录制

首先通过下面的命令查看一下 mac 上都有哪些设备。
ffmpeg -f avfoundation -list_devices true -i “”

录屏

ffmpeg -f avfoundation -i 1 -r 30 out.yuv
-f 指定使用 avfoundation 采集数据。
-i 指定从哪儿采集数据,它是一个文件索引号。在我的MAC上,1代表桌面(可以通过上面的命令查询设备索引号)。
-r 指定帧率。按ffmpeg官方文档说-r与-framerate作用相同,但实际测试时发现不同。-framerate 用于限制输入,而-r用于限制输出。
注意,桌面的输入对帧率没有要求,所以不用限制桌面的帧率。其实限制了也没用。
录屏+声音

ffmpeg -f avfoundation -i 1:0 -r 29.97 -c:v libx264 -crf 0 -c:a libfdk_aac -profile:a aac_he_v2 -b:a 32k out.flv
-i 1:0 冒号前面的 “1” 代表的屏幕索引号。冒号后面的”0″代表的声音索相号。
-c:v 与参数 -vcodec 一样,表示视频编码器。c 是 codec 的缩写,v 是video的缩写。
-crf 是 x264 的参数。 0 表式无损压缩。
-c:a 与参数 -acodec 一样,表示音频编码器。
-profile 是 fdk_aac 的参数。 aac_he_v2 表式使用 AAC_HE v2 压缩数据。
-b:a 指定音频码率。 b 是 bitrate的缩写, a是 audio的缩与。

录视频

ffmpeg -framerate 30 -f avfoundation -i 0 out.mp4
-framerate 限制视频的采集帧率。这个必须要根据提示要求进行设置,如果不设置就会报错。
-f 指定使用 avfoundation 采集数据。
-i 指定视频设备的索引号。
视频+音频

ffmpeg -framerate 30 -f avfoundation -i 0:0 out.mp4
录音

ffmpeg -f avfoundation -i :0 out.wav
录制音频裸数据

ffmpeg -f avfoundation -i :0 -ar 44100 -f s16le out.pcm

分解与复用

流拷贝是通过将 copy 参数提供给-codec选项来选择流的模式。它使得ffmpeg省略了指定流的解码和编码步骤,所以它只能进行多路分解和多路复用。 这对于更改容器格式或修改容器级元数据很有用。 在这种情况下,上图将简化为:

由于没有解码或编码,速度非常快,没有质量损失。 但是,由于许多因素,在某些情况下可能无法正常工作。 应用过滤器显然也是不可能的,因为过滤器处理未压缩的数据。

抽取音频流

ffmpeg -i input.mp4 -acodec copy -vn out.aac
acodec: 指定音频编码器,copy 指明只拷贝,不做编解码。
vn: v 代表视频,n 代表 no 也就是无视频的意思。
抽取视频流

ffmpeg -i input.mp4 -vcodec copy -an out.h264
vcodec: 指定视频编码器,copy 指明只拷贝,不做编解码。
an: a 代表视频,n 代表 no 也就是无音频的意思。
转格式

ffmpeg -i out.mp4 -vcodec copy -acodec copy out.flv
上面的命令表式的是音频、视频都直接 copy,只是将 mp4 的封装格式转成了flv。

音视频合并
ffmpeg -i out.h264 -i out.aac -vcodec copy -acodec copy out.mp4

处理原始数据
提取YUV数据

ffmpeg -i input.mp4 -an -c:v rawvideo -pixel_format yuv420p out.yuv
ffplay -s wxh out.yuv
-c:v rawvideo 指定将视频转成原始数据
-pixel_format yuv420p 指定转换格式为yuv420p
YUV转H264

ffmpeg -f rawvideo -pix_fmt yuv420p -s 320×240 -r 30 -i out.yuv -c:v libx264 -f rawvideo out.h264
提取PCM数据

ffmpeg -i out.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm
ffplay -ar 44100 -ac 2 -f s16le -i out.pcm
PCM转WAV

ffmpeg -f s16be -ar 8000 -ac 2 -acodec pcm_s16be -i input.raw output.wav

滤镜

在编码之前,ffmpeg可以使用libavfilter库中的过滤器处理原始音频和视频帧。 几个链式过滤器形成一个过滤器图形。 ffmpeg区分两种类型的过滤器图形:简单和复杂。
简单滤镜

简单的过滤器图是那些只有一个输入和输出,都是相同的类型。 在上面的图中,它们可以通过在解码和编码之间插入一个额外的步骤来表示:

简单的filtergraphs配置了per-stream-filter选项(分别为视频和音频使用-vf和-af别名)。 一个简单的视频filtergraph可以看起来像这样的例子:

请注意,某些滤镜会更改帧属性,但不会改变帧内容。 例如。 上例中的fps过滤器会改变帧数,但不会触及帧内容。 另一个例子是setpts过滤器,它只设置时间戳,否则不改变帧。
复杂滤镜

复杂的过滤器图是那些不能简单描述为应用于一个流的线性处理链的过滤器图。 例如,当图形有多个输入和/或输出,或者当输出流类型与输入不同时,就是这种情况。 他们可以用下图来表示:

复杂的过滤器图使用-filter_complex选项进行配置。 请注意,此选项是全局性的,因为复杂的过滤器图形本质上不能与单个流或文件明确关联。
-lavfi选项等同于-filter_complex。
一个复杂的过滤器图的一个简单的例子是覆盖过滤器,它有两个视频输入和一个视频输出,包含一个视频叠加在另一个上面。 它的音频对应是amix滤波器。
添加水印

ffmpeg -i out.mp4 -vf “movie=logo.png,scale=64:48[watermask];[in][watermask] overlay=30:10 [out]” water.mp4
-vf中的 movie 指定logo位置。scale 指定 logo 大小。overlay 指定 logo 摆放的位置。

删除水印
先通过 ffplay 找到要删除 LOGO 的位置

ffplay -i test.flv -vf delogo=x=806:y=20:w=70:h=80:show=1
使用 delogo 滤镜删除 LOGO

ffmpeg -i test.flv -vf delogo=x=806:y=20:w=70:h=80 output.flv
视频缩小一倍

ffmpeg -i out.mp4 -vf scale=iw/2:-1 scale.mp4
-vf scale 指定使用简单过滤器 scale,iw/2:-1 中的 iw 指定按整型取视频的宽度。 -1 表示高度随宽度一起变化。
视频裁剪

ffmpeg -i VR.mov -vf crop=in_w-200:in_h-200 -c:v libx264 -c:a copy -video_size 1280×720 vr_new.mp4
crop 格式:crop=out_w:out_h❌y
out_w: 输出的宽度。可以使用 in_w 表式输入视频的宽度。
out_h: 输出的高度。可以使用 in_h 表式输入视频的高度。
x : X坐标
y : Y坐标
如果 x和y 设置为 0,说明从左上角开始裁剪。如果不写是从中心点裁剪。

倍速播放

ffmpeg -i out.mp4 -filter_complex “[0:v]setpts=0.5PTS[v];[0:a]atempo=2.0[a]” -map “[v]” -map “[a]” speed2.0.mp4
-filter_complex 复杂滤镜,[0:v]表示第一个(文件索引号是0)文件的视频作为输入。setpts=0.5PTS表示每帧视频的pts时间戳都乘0.5 ,也就是差少一半。[v]表示输出的别名。音频同理就不详述了。
map 可用于处理复杂输出,如可以将指定的多路流输出到一个输出文件,也可以指定输出到多个文件。”[v]” 复杂滤镜输出的别名作为输出文件的一路流。上面 map的用法是将复杂滤镜输出的视频和音频输出到指定文件中。

对称视频

ffmpeg -i out.mp4 -filter_complex “[0:v]pad=w=2*iw[a];[0:v]hflip[b];[a][b]overlay=x=w” duicheng.mp4
hflip 水平翻转

如果要修改为垂直翻转可以用vflip。
画中画
ffmpeg -i out.mp4 -i out1.mp4 -filter_complex “[1:v]scale=w=176:h=144:force_original_aspect_ratio=decrease[ckout];[0:v][ckout]overlay=x=W-w-10:y=0[out]” -map “[out]” -movflags faststart new.mp4
录制画中画
ffmpeg -f avfoundation -i “1” -framerate 30 -f avfoundation -i “0:0”
-r 30 -c:v libx264 -preset ultrafast
-c:a libfdk_aac -profile:a aac_he_v2 -ar 44100 -ac 2
-filter_complex “[1:v]scale=w=176:h=144:force_original_aspect_ratio=decrease[a];[0:v][a]overlay=x=W-w-10:y=0[out]”
-map “[out]” -movflags faststart -map 1:a b.mp4
多路视频拼接
ffmpeg -f avfoundation -i “1” -framerate 30 -f avfoundation -i “0:0” -r 30 -c:v libx264 -preset ultrafast -c:a libfdk_aac -profile:a aac_he_v2 -ar 44100 -ac 2 -filter_complex “[0:v]scale=320:240[a];[a]pad=640:240[b];[b][1:v]overlay=320:0[out]” -map “[out]” -movflags faststart -map 1:a c.mp4
音视频的拼接与裁剪
裁剪
ffmpeg -i out.mp4 -ss 00:00:00 -t 10 out1.mp4
-ss 指定裁剪的开始时间,精确到秒
-t 被裁剪后的时长。
合并
首先创建一个 inputs.txt 文件,文件内容如下:
file ‘1.flv’
file ‘2.flv’
file ‘3.flv’
然后执行下面的命令:
ffmpeg -f concat -i inputs.txt -c copy output.flv
hls切片
ffmpeg -i out.mp4 -c:v libx264 -c:a libfdk_aac -strict -2 -f hls out.m3u8
-strict -2 指明音频使有AAC。
-f hls 转成 m3u8 格式。
视频图片互转
视频转JPEG
ffmpeg -i test.flv -r 1 -f image2 image-%3d.jpeg
视频转gif
ffmpeg -i out.mp4 -ss 00:00:00 -t 10 out.gif
图片转视频
ffmpeg -f image2 -i image-%3d.jpeg images.mp4
直播相关
推流
ffmpeg -re -i out.mp4 -c copy -f flv rtmp://server/live/streamName
拉流保存
ffmpeg -i rtmp://server/live/streamName -c copy dump.flv
转流
ffmpeg -i rtmp://server/live/originalStream -c:a copy -c:v copy -f flv rtmp://server/live/h264Stream
实时推流
ffmpeg -framerate 15 -f avfoundation -i “1” -s 1280×720 -c:v libx264 -f flv rtmp://localhost:1935/live/room
ffplay
播放YUV 数据
ffplay -pix_fmt nv12 -s 192×144 1.yuv
播放YUV中的 Y平面
ffplay -pix_fmt nv21 -s 640×480 -vf extractplanes=‘y’ 1.yuv

处理流程
输入文件->demuxer->编码数据包->decoder->解码后数据帧->encoder->编码数据包->muxer->输出文件

OpenVidu

https://openvidu.io/

1) 克隆教程:

git clone https://github.com/OpenVidu/openvidu-tutorials.git

2) 您需要在开发计算机中安装http Web server 才能执行本教程。 如果安装了node.js,则可以使用 http-server 来提供应用程序文件。 通过如下命令安装:

npm install -g http-server

3) 运行教程:

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

http-server -S -C cert.pem openvidu-tutorials/openvidu-hello-world/web

4) openvidu-server 和 Kurento Media Server 必须在您开发计算机中启动并运行。 最简单的方法是使用Docker容器运行(也可以参考前一篇文字的安装方式):

docker run -p 4443:4443 –rm -e openvidu.secret=MY_SECRET openvidu/openvidu-server-kms

5)一旦服务器运行,我们可以使用浏览器打开https://localhost:8080来测试应用程序。 第一次使用docker容器并加入视频通话时,会提示您接受openvidu-server的自签名证书。

如果您使用的是Windows,请阅读此常见问题解答以正确运行本教程

要了解使用OpenVidu开发的一些技巧,请查看此常见问题解答

二、源码解析

这个应用程序非常简单。 它只有4个文件:

openvidu-browser-VERSION.js:openvidu-browser 库文件, 您不必操纵此文件。app.js:示例应用程序主JavaScritp文件,它使用了 openvidu-browser-VERSION.js。style.css:一些用于样式index.html的CSS类。index.html:表单的HTML代码,用于连接视频通话。 它链接到两个JavaScript文件:
<script src="openvidu-browser-VERSION.js"></script>
<scriptsrc="app.js"></script>

让我们看看在 app.js 中如何使用openvidu-browser-VERSION.js:

第一行声明了代码中不同会话点所需的变量

var OV;
var session;

OV 是我们的 OpenVidu 对象(libray的入口点)。 session是我们视频通话的连接。 作为joinSession() 方法中的第一句,将识别我们视频调用的变量进行初始化,该视频调用从HTML输入中检索值。

var mySessionId = document.getElementById(“sessionId”).value;

初始化 new session 及其 event

OV = new OpenVidu();
session = OV.initSession();

session.on(‘streamCreated’, function (event) {
session.subscribe(event.stream, ‘subscriber’);
});

正如您在代码中看到的,该过程非常简单:获取OpenVidu对象并使用它初始化Session对象。

然后,您可以订阅会话所需的所有事件。 在这种情况下,我们只想订阅会话中正在创建的每个流:在streamCreated上,我们订阅特定的流,在event.stream属性中可用。

您可以查看参考文档中的所有事件

从OpenVidu Server获取token

注意:这就是本教程是一个不安全的应用程序的原因。 我们需要向OpenVidu Server请求用户令牌才能连接到我们的会话。 这个过程应该完全在我们的服务器端进行,而不是在我们的客户端。 但是由于本教程中缺少应用程序后端,JavaScript代码本身将对OpenVidu Server执行POST操作

getToken(mySessionId).then(token => {
// See next point to see how to connect to the session using ‘token’
});

现在我们需要一个来自OpenVidu Server的token。 在生产环境中,我们使用 REST API,OpenVidu Java Client 或 OpenVidu Node Client 在应用程序后端执行此操作。 在这里我们已经在一个getToken()方法中实现了向 OpenVidu Server 发送POST请求,这个 getToken 返回一个带有token的Promise。 没有太多细节,这个方法对 OpenVidu Server 执行两个ajax请求,传递 OpenVidu Server secret来验证它们:

首先,ajax执行POST请求到 /api /sessions(我们发送一个customSessionId字段来命名会话,并使用从HTML输入中检索到的mySessionId值)第二个Ajax将POST请求传递给 /api/token(我们发送一个sessionId字段来将该token分配给同一个会话)

您可以在GitHub仓库中详细检查此方法。

使用token连接到session

getToken(mySessionId).then(token => {

session.connect(token)
.then(() => {
document.getElementById(“session-header”).innerText = mySessionId;
document.getElementById(“join”).style.display = “none”;
document.getElementById(“session”).style.display = “block”;

  var publisher = OV.initPublisher("publisher");
  session.publish(publisher);
})
.catch(error => {
  console.log("There was an error connecting to the session:", error.code, error.message);
});

});

我们只需要调用session.connect 并向 OpenVidu Server 传递最近获取到的token。 此方法返回您可以订阅的Promise。

如果订阅成功,我们首先将视图设置为活动视频会话。 然后继续发布我们的摄像头。 为此,我们需要使用 OpenVidu.initPublisher 方法生成发布者,一个显示我们网络摄像头的新HTML视频将被添加到ID为“publisher”的元素内的页面中。

最后比较重要的一点,我们发布这个 publisher 对象需要使用 session.publish。 此时,连接到此会话的其他用户将触发其自己的streamCreated事件,并可以开始观看我们的网络摄像头。

断开会话

session.disconnect();

无论何时我们想要用户断开会话,我们只需要调用session.disconnect方法。 在这里它会调用内部的 leaveSession 函数,当用户点击“LEAVE”按钮时触发。 该功能也将页面返回到“Join session”视图。

Kurento

主页: http://www.kurento.org/
github: https://github.com/kurento
服务端采用C++实现: https://github.com/Kurento/kurento-media-server
Docker https://hub.docker.com/r/kurento/kurento-media-server
说明文档 https://doc-kurento.readthedocs.io/en/stable/

Kurento模块分为三类:
主要模块与Kurento Media Server开箱即用合并:
kms-core:Kurento Media Server的主要组件。
kms-elements:Kurento Media Elements的实现(WebRtcEndpoint,PlayerEndpoint等)
kms-filters:
Kurento过滤器的实现(FaceOverlayFilter,ZBarFilter等)
内置模块Kurento团队开发的额外模块,用于增强Kurento Media Server的基本功能。到目前为止,有四个内置模块,分别是:
kms-platedetector:用于检测视频流中的车牌的过滤器。
kms-pointerdetector:基于颜色跟踪检测视频流中指针的过滤器。
kms-chroma:过滤器,它在顶层使用颜色范围并使之透明,从而在后面显示另一个图像。
kms-crowddetector:用于检测视频流中人聚集的过滤器。
定制模块

 docker run --name kms -d -p 8888:8888 \
  -e KMS_STUN_IP= \
  -e KMS_STUN_PORT=3478 \
  -e KMS_TURN_URL=user@password:urlorIp:3478 \
   kurento/kurento-media-server:latest

  -e KMS_NETWORK_INTERFACES= \
  -e KMS_EXTERNAL_ADDRESS= \
  -e KMS_MIN_PORT= \
  -e KMS_MAX_PORT= \
  -e KMS_MTU=1200 \
    kurento/kurento-media-server:latest
配制文件位置
/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini
/etc/kurento/modules/kurento/BaseRtpEndpoint.conf.ini
#查看KMS日志
docker logs kms
#实时查看:
docker logs -f kms
日志输出
    docker logs --follow kms >"kms-$(date '+%Y%m%dT%H%M%S').log" 2>&1

    检查KMS是否已启动并正在侦听连接,请使用以下命令:
curl \
    --include \
    --header "Connection: Upgrade" \
    --header "Upgrade: websocket" \
    --header "Host: 127.0.0.1:8888" \
    --header "Origin: 127.0.0.1" \
    http://127.0.0.1:8888/kurento
应该得到类似于以下内容的响应:
HTTP/1.1 500 Internal Server Error
Server: WebSocket++/0.7.0

#进入镜像
docker exec -it kms /bin/bash
#安装vim
apt-get update
apt-get install vim
#进入配置文件夹
cd /etc/kurento/modules/kurento/
#编辑配置文件
vim WebRtcEndpoint.conf.ini
stunServerAddress=xx.xx.xx.xx
stunServerPort=pp
turnURL=username:userpwd@xx.xx.xx.xx:pp?transport=tcp
or
修改docker运行的kms配置文件方法
1.复制容器中的 配置文件到 宿主机中
docker cp  kms:/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini  ~/WebRtcEndpoint.conf.ini
2.修改配置文件
vim ~/WebRtcEndpoint.conf.ini
3.宿主机配置文件 复制到 kms容器中
 docker cp ~/WebRtcEndpoint.conf.ini kms:/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini

#查看当前启动的容器
docker ps
docker restart  {kurento容器ID}

kurento相关配置
1、Kurento Media Server 日志
Kurento Media Server日志文件存储在 /var/log/kurento-media-server/文件夹中。 此文件夹的内容如下:
    media-server_.<log_number>.<kms_pid>.log: Kurento Media Server的当前日志
    media-server_error.log: 第三方错误
    logs: 包含KMS已旋转日志的文件夹
2、Kurento Media Server 配置
    /etc/default/kurento-media-server 默认配置
    /etc/kurento/kurento.conf.json 通用配置
    /etc/kurento/modules/kurento/MediaElement.conf.ini Media Elements 通用参数。
    /etc/kurento/modules/kurento/SdpEndpoint.conf.ini SdpEndpoints的音频/视频参数( 例如: WebRtcEndpoint and RtpEndpoint)。
    /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini WebRtcEndpoint 特定参数。
    /etc/kurento/modules/kurento/HttpEndpoint.conf.ini HttpEndpoint 特定参数。

#### kurento-hello-world
““
git clone https://github.com/Kurento/kurento-tutorial-java.git
cd kurento-tutorial-java/kurento-hello-world
vim src/main/resources/static/js/index.js
在函数function uiStart()里,增加一个叫iceservers的变量,格式如下:
var iceservers={
“iceServers”:[
{
urls:”stun:xx.xx.xx.xx:3478″
},
{
urls:[“turn:xx.xx.xx.xx:3478″]
username:”xxxx”,
credential: “xxxx”
}
]
}
再修改底下的options变量:
const options = {
localVideo: uiLocalVideo,
remoteVideo: uiRemoteVideo,
mediaConstraints: { audio: true, video: true },
onicecandidate: (candidate) => sendMessage({
id: ‘ADD_ICE_CANDIDATE’,
candidate: candidate,
}),
configuration: iceservers //修改在这里,增加了一个configuration的key
};

启动项目
mvn -U clean spring-boot:run -Dkms.url=ws://xx.xx.xx.xx:8888/kurento

用 idea 打开 kurento-hello-world 项目,下载 maven 依赖完成后,在 run configurations 中添加 new configurations。
选择 maven , command line 中输入:
spring-boot:run -Dkms.url=ws://:8888/kurento # 这里的 public-ip 添你安装 kms 的服务器公网 ip 地址

启动完之后用谷歌或者火狐浏览器打开demo页面https://localhost:8443/
点击start启动

运行 hello world 示例时,会遇到 使用websocket传输内容过长的问题
//项目中创建 package org.kurento.tutorial.helloworld.config
//config 包下创建类
package org.kurento.tutorial.helloworld.config;

@Configuration
//@ComponentScan
//@EnableAutoConfiguration
public class WebAppRootContext implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println(“org.apache.tomcat.websocket.textBufferSize”);
servletContext.addListener(WebAppRootListener.class);
servletContext.setInitParameter(“org.apache.tomcat.websocket.textBufferSize”,”1024000″);
}

}
““

API Java SDK for Kurento Media Server

https://github.com/Kurento/kurento-java

Kurento tutorials for Node JS

https://github.com/Kurento/kurento-tutorial-node

信令服务器与web客户端 kurento-room

https://github.com/Kurento/kurento-room

NUBOMEDIA

NUBOMEDIA Autonomous Installer
https://nubomedia.readthedocs.io/en/latest/tools/autonomous-installer/

Android客户端开源库

https://github.com/nubomedia-vtt/nubo-test

iOS客户端开源库

https://github.com/nubomediaTI/Kurento-iOS

ffmpeg转发模块

利用ffmpeg可执行文件将本地RTP流封装转发成RTMP推送出去,具体可以参考这个开源工程:
kurento-rtmp https://github.com/godka/kurento-rtmp

gstreamer转发模块

RTP解包 —— 音视频转换 —— FLV封包 —— RTMP推流

openssl 生成公钥、密钥及.pem文件

首先得安装OpenSSL软件包openssl,安装了这个软件包之后,我们可以做这些事情:
o Creation of RSA, DH and DSA Key Parameters # 创建密钥 key
o Creation of X.509 Certificates, CSRs and CRLs # 创建证书
o Calculation of Message Digests #
o Encryption and Decryption with Ciphers # 加密、解密
o SSL/TLS Client and Server Tests # SSL 服务器端/客户端测试
o Handling of S/MIME signed or encrypted Mail # 处理签名或加密了的邮件

1、生成RSA密钥的方法生成根证书私钥(pem文件)
openssl genrsa -des3 -out privkey.pem 2048
这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码,(转换无密码key:openssl rsa -in privkey.pem -out privkey_nopass.pem);
or 如果你不想要每次都输入密码,可以改成:
openssl genrsa -out privkey.pem 2048
建议用2048位密钥,少于此可能会不安全或很快将不安全。

2、生成一个证书请求CSR 生成根证书签发申请文件(csr文件)
openssl req -new -key privkey.pem -out cert.csr
这个命令将会生成一个证书请求,当然,用到了前面生成的密钥privkey.pem文件
这里将生成一个新的文件cert.csr,即一个证书请求文件,你可以拿着这个文件去数字证书颁发机构(即CA)申请一个数字证书。CA会给你一个新的文件cacert.pem,那才是你的数字证书。

#自签发根证书(cer文件)
openssl x509 -req -days 365 -sha1 -extensions v3_ca -signkey privkey.pem -in cert.csr -out cacert.pem
如果是自己做测试,那么证书的申请机构和颁发机构都是自己。就可以用下面这个命令来生成证书:
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
这个命令将用上面生成的密钥privkey.pem生成一个数字证书cacert.pem

3、使用数字证书和密钥
有了privkey.pem和cacert.pem文件后就可以在自己的程序中使用了

#生成服务端私钥
openssl genrsa -out key.pem 2048
#生成证书请求文件
openssl req -new -key key.pem -out server.csr -subj “/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myServer”
#使用根证书签发服务端证书
openssl x509 -req -days 365 -sha1 -extensions v3_req -CA cacert.pem -CAkey privkey.pem -CAserial cert.srl -CAcreateserial -in server.csr -out cert.pem
#使用CA证书验证server端证书
openssl verify -CAfile cacert.pem cert.pem

WIN7用户目录位置要怎么更改到D盘里

  1. 去掉Administrator“帐户已禁用”之前的勾,而后关闭“计算机管理器”;

  2. 注销当前用户(注意,不是“切换用户”),而后以“Administrator”登录

  3. robocopy “C:\Users” “D:\Users” /E /COPYALL /XJ /XD “C:\Users\Administrator”

  4. 注销Administrator,重新使用用户名登录;

  5. 以管理员身份打开一个DOS窗口,输入以下命令:
    rmdir “C:\Users” /S /Q
    mklink /J “C:\Users” “D:\Users”

Emmet

Emmet (前身为 Zen Coding) 是一个能大幅度提高前端开发效率的一个工具

Emmet 官网: http://emmet.io
Emmet 官网文档:http://docs.emmet.io/
Emmet 速查表: http://docs.emmet.io/cheat-sheet/
Emmet 项目主页:https://github.com/emmetio/emmet

IntelliJ IDEA 自带 Emmet 功能,使用的快捷键是 Tab
在File -> Settings -> Editor -> Emmet下可以针对IntelliJ IDEA对Emmet的支持情况进行设置

编辑器中输入缩写代码:ul>li*5 ,然后按下拓展键(默认为tab),即可得到代码片段:

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>

html:5 或!:用于HTML5文档类型
html:xt:用于XHTML过渡文档类型
html:4s:用于HTML4严格文档类型

连续输入元素名称和ID,Emmet会自动为你补全,比如输入p#foo: 

>:子元素符号,表示嵌套的元素
+:同级标签符号
^:可以使该符号前的标签提升一行

嵌套和括号来快速生成一些代码块,比如输入(.foo>h1)+(.bar>h2),

声明一个带类的标签,只需输入div.item,就会生成<div class="item"></div>。
li:用于ul和ol中
tr:用于table、tbody、thead和tfoot中
td:用于tr中
option:用于select和optgroup中

要定义多个元素,可以使用*符号。比如,ul>li*3

二、CSS缩写
1.  值 比如要定义元素的宽度,只需输入w100
单位别名列表:
p 表示%
e 表示 em
x 表示 ex

如果有些缩写你拿不准,Emmet会根据你的输入内容匹配最接近的语法,比如输入ov:h、ov-h、ovh和oh,生成的代码是相同的

如果输入非W3C标准的CSS属性,Emmet会自动加上供应商前缀,比如输入trs
也可以在任意属性前加上“-”符号,也可以为该属性加上前缀。比如输入-super-foo
不希望加上所有前缀,可以使用缩写来指定,比如-wm-trf表示只加上-webkit和-moz前缀

渐变 输入lg(left, #fff 50%, #000)

生成Lorem ipsum文本 

Lorem ipsum指一篇常用于排版设计领域的拉丁文文章,主要目的是测试文章或文字在不同字型、版型下看起来的效果。通过Emmet,你只需输入lorem 或 lipsum即可生成这些文字。还可以指定文字的个数,比如lorem10

定制Emmet插件: 
添加新缩写或更新现有缩写,可修改snippets.json文件
更改Emmet过滤器和操作的行为,可修改preferences.json文件
定义如何生成HTML或XML代码,可修改syntaxProfiles.json文件

python开发工具

pycharm
https://www.jetbrains.com/pycharm/

IDEA加装插件
python
python文件都必须要有明确的程序入口才能执行,不像自己随便写写的一个print一样。也就是说,必须要有

if __name__ == '__main__':

axios

安装axios
npm install axios --save

直接script标签引用
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

ES6 import引用
因为axios不是vue的插件,所以不能直接用use方法,需要将其加载到原型上。
import axios from 'axios'
axios.get()

如果要全局使用axios就需要在main.js中设置成全局的,然后再组件中通过this调用
import axios from 'axios'
Vue.prototype.$axios = axios
this.$axios.get()

使用

发送一个最简单的请求
这里我们发送一个带参数的get请求,params参数放在get方法的第二个参数中,如果没有参数get方法里可以只写路径。如果请求失败捕获一下异常。

axios
  .get('http://rap2api.taobao.org/app/mock/23080/resources/search',{
      params: {
         id: 5
      }
   })
  .then(res => {
    console.log('数据是:', res);
  })
  .catch((e) => {
    console.log('获取数据失败');
  });

当然,我们也可以发送一个POST请求,post方法的第二个参数为请求参数对象。

this.$axios.post('http://rap2api.taobao.org/app/mock/121145/post',{
  name: '小月'
})
.then(function(res){
  console.log(res);
})
.catch(function(err){
  console.log(err);
});

一次合并发送多个请求
分别写两个请求函数,利用axios的all方法接收一个由每个请求函数组成的数组,可以一次性发送多个请求,如果全部请求成功,在axios.spread方法接收一个回调函数,该函数的参数就是每个请求返回的结果。

function getUserAccount(){
  return axios.get('/user/12345');
}
function getUserPermissions(){
  return axios.get('/user/12345/permissions');
}
this.$axios.all([getUserAccount(),getUserPermissions()])
  .then(axios.spread(function(res1,res2){
    //当这两个请求都完成的时候会触发这个函数,两个参数分别代表返回的结果
}))

axios的API
以上通过axios直接调用发放来发起对应的请求其实是axios为了方便起见给不同的请求提供的别名方法。我们完全可以通过调用axios的API,传递一个配置对象来发起请求。

发送post请求,参数写在data属性中

axios({
  url: 'http://rap2api.taobao.org/app/mock/121145/post',
  method: 'post',
  data: {
    name: '小月'
  }
}).then(res => {
  console.log('请求结果:', res);
});

发送get请求,默认就是get请求,直接第一个参数写路径,第二个参数写配置对象,参数通过params属性设置。

axios('http://rap2api.taobao.org/app/mock/121145/get', {
  params: {
    name: '小月'
  }
}).then(res => {
  console.log('请求结果:', res);
});

axios为所有请求方式都提供了别名:

axios.request(config)
axios.get(url, [config])
axios.delete(url, [config])
axios.head(url, [config])
axios.options(url, [config])
axios.post(url, [data], [config])
axios.put(url, [data], [config])
axios.patch(url, [data], [config])

axios配置默认值
1、可以通过axios.defaults设置全局默认值,在所有请求中都生效。
axios.defaults.headers.common[“token”] = “”
axios.defaults.headers.post[“Content-type”] = “application/json”
axios.defaults.baseURL = ‘https://service.xxx.com; //设置统一路径前缀

2、也可以自定义实例的默认值,以及修改实例的配置
// 创建时自定义默认配置,超时设置为全局默认值0秒
let ax = axios.create({
baseURL: ‘http://rap2api.taobao.org’,
params: { name: ‘小月’ }
});
// 修改配置后,超时设置为4秒
ax.defaults.timeout = 4000;

3、也可以像前面那样,在每个请求中设置相关的配置。
axios(‘/app/mock/121145/get’, {
params: {
name: ‘xiaoxiao’
},
baseURL: ‘http://rap2api.taobao.org’
})
以上配置方法优先级从1-3依次增高,更多配置选项查看文档。

{
method:’请求方法’,
baseURL:’如果路径不是绝对路径,就会在路径前自动添加此路径’,
transformRequest: [(data, header)=>{}], //在发送请求之前修改数据,适用于post、put、patch
transformResponse: [(data)=>{
return JSON.parse(data).data;
}], //在收到的数据传到then之前修改数据,注意这里data是个字符串类型。
header: {‘X-Requested-With’: ‘XMLHttpRequest’}, //请求头
params: {}, //请求参数
paramsSerializer: (params)=>{
return qs.stringify(params); //name=xiaohong&id=1
} //可选函数,可以把参数拼接成字符串
data: {}, // post类方法的请求体参数
timeout: 0, //请求延时事件,如果超时请求终止
withCredentials: false, //是否时跨站点请求
onUploadProgress: (progressEvent)=>{
//可以通过progressEvent拿到上传的进度
},
onDownloadProgress: ()=>{},//和onUploadProgress一样,获取下载的进度
responseType: json, // 返回的数据格式
maxContentLength: 2000, //相应内容的最大尺寸
validateStatus: (validateStatus)=>{
return validateStatus >= 200; //限制相应状态码,如果不满足就拒绝
},
cancelToken: new cancelToken(function(cancel){}) // 指定一个取消请求标识,下面会用到
}

拦截器
可以分别设置请求拦截和响应拦截,在发出请求和响应到达then之前进行判断处理。

axios.interceptors.response.use(
  res => {
    if (res) {
      return res;
    }
  },
  err => {
    return Promise.reject(error);
  }
);

以上以相应拦截器为例,请求拦截器同样,只是把response换成request。第一个参数是成功回调,第二个是错误回调。
也可以移除拦截器,就像移除js定时器一样的操作:

var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

取消请求
1、取消请求的话需要先通过创建一个CancelToken.source工厂函数创建一个标识source
2、通过配置项制定标识,这样才知道取消的是哪个请求
3、调用取消方法

var CancelToken = axios.CancelToken;
var source = CancelToken.source(); //1
axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token //2
})
source.cancel('Operation canceled by the user.'); //3

还有一种写法是直接把cancelToken的构造函数传递给配置项,该构造函数接受一个函数作为参数,在这个函数中指定标识符。

var CancelToken = axios.CancelToken;
var cancel;
axios.get('/app/mock/121145/get', {
  baseURL: 'http://rap2api.taobao.org',
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});
cancel();

跨域配置
如果我们要跨域请求数据,在配置文件里设置代理,vue-cli3项目,需要在根目录自己创建一个vue.config.js,在里面写配置。

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://www.xxx.com', //目标路径,别忘了加http和端口号
        changeOrigin: true, //是否跨域
        ws: true,
        pathRewrite: {
          '^/api': '' //重写路径
        }
      }
    }
  }
};

调用接口:
axios.post(‘/api/test’, {name: ‘xiao’});
如果没有重写路径,访问的就是https://www.xxx.com/api/test,如果像上面代码那样重写路径访问的就是https://www.xxx.com/test。

less less-loader

npm install less less-loader --save-dev
yarn add less less-loader --dev
````

[官网](https://less.bootcss.com/ "官网")https://less.bootcss.com/

在 Node.js 环境中使用 Less :
npm install -g less
> lessc styles.less styles.css

在浏览器环境中使用 Less :

““