EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
1. FFmpeg的安装 FFmpeg是用来记录、转换数字音频、视频的开源软件,它支持文件和网络流操作。它支持以函数库的方式使用,所以有很多软件都依赖它,比如VLC、暴风影音、腾讯会议等。它的命令行程序也非常强大,各种命令行选项学起来虽然困难,但是几乎能够满足日常对音视频的各种处理需求。今天我们就通过飞凌嵌入式OKA40i-C开发板保定飞凌嵌入式技术有限公司来介绍它的命令行工作方式。 1 A) F: f" k0 r+ E
FFmpeg提供了全部源代码,所以在网上可以找到很多教程是关于交叉编译ARM版本的。我们测试的版本使用的是FFmpeg-release-armel-static.tar.xz。解压缩以后拷贝到飞凌嵌入式OKA40i-C开发板上并设置好权限就可以使用了。
: s3 W0 H2 @+ S# @; j$ x2. USB摄像头测试 OKA40i-C开发板接口丰富,它支持USB摄像头、CMOS-OV5640摄像头、模拟摄像头。把USB摄像头插入开发板,然后使用 - 6 A- F) Y0 U) l$ F% h9 p. M, O
v4l2-ctl --list-devices
6 \2 W% W7 ^+ ~0 L$ ]9 a4 J可以看到/dev/video0就是我们的USB摄像头,如下图。 ![]()
使用下面的命令可以看到该摄像头的全部参数: v4l2-ctl -d /dev/video0 --all
3 W* b$ a0 k, w7 F2 s, v4 X$ |, @3 @ t
& G' I* ?5 Y' ^: o
) [: A8 ~! \& m' K5 U
. R# b4 ~* X8 B1 b$ R% o+ Q: K* [( F6 t6 ^
Driver Info (not using libv4l2):6 ~* B# Y% f$ ` ]2 y4 Q! J* [
/ z& s& F& i r- J: |5 [$ e, K( m- 6 y' S0 z1 |/ f$ J
) n/ f3 @' Q1 O+ { Driver name : uvcvideo. C3 q( X! c% N7 C1 n% e
- x- \: B. m2 |* d+ c
- , {2 q X" t3 M' z' | Q0 @
- Z, W& d$ _' U& s) s* o0 D2 M' _
Card type : USB2.0 PC CAMERA7 a& y6 b& l" D% {0 [2 M4 m1 }
5 r: O3 A" N5 T) O* ] - * K# a5 @% S& u! A
: U! d4 m; k1 ~
Bus info : usb-sunxi-ehci-1$ O: n7 v2 @# @3 ], J6 |4 [
/ F0 k6 D# [, w" H# t' N
% P0 m2 Q+ f O; m: E# ]8 t' Z9 h0 Q
Driver version : 3.10.65! [9 V9 T4 r/ P
5 Z3 @; W$ j% c5 Y& [
- 3 T8 B! Y/ W( h+ B) f
0 k; _: c: R4 q2 U1 b4 j j
Capabilities : 0x04000001. `2 p) h# x' _7 F
/ L% b# s7 L8 }" i
/ o2 ^# N3 h" f- E* H8 t" Y m4 o0 Z; I6 n3 [" K, H; M% b, r
Video Capture1 c; {1 c$ y, k% d3 q
: h. h6 u- U, ^+ T- J2 a, I- 7 V. T' v4 a% @3 Y
- `! c6 F3 o$ S: q0 D$ s; `& Z' ] Streaming* I' j1 Y9 D4 s
9 N8 r. x1 h/ ^- y7 o
: @, v% P& @5 m7 K$ R& \$ A( ?/ p* N+ _. J2 l0 @2 p/ T9 Z
Video input : 0 (Camera 1: ok)
1 \# L. y- `' j8 p4 E1 e' h) G' l c1 N. R
, Z, e3 }6 G0 o: V4 ^6 e4 t, E3 L u! b9 X9 \4 K
Format Video Capture:
0 c1 d& K, }* ]; m; C' H# J" n2 |7 f. }# K2 p, m
- 9 V: t/ I: X% n- E1 Q8 s
' q* J9 v+ M+ g
Width/Height : 640/480" o8 p. g' e: g: A7 U& ?+ c
& | c' w7 r" R% I( h8 H/ e! ^ - , J O8 K( `# y. L. V& x
4 q7 a, |" b2 T8 n$ A4 Y Pixel Format : 'YUYV'0 i! Z) k# n( m" M$ I! ^
2 I; ~1 }+ I: ^ - / }# I; k3 v7 ^& Y
8 J, `7 t) i) @ E+ c6 j' P8 x/ s Field : None
8 p, y& ~ o5 ?; \+ M* D
( U2 b' I- |9 R( c; B/ r
4 Y9 x: Q. G5 H5 q
8 R7 C, Q3 O$ T1 O. R$ p- m* H Bytes per Line : 1280/ G/ O! y3 A) D# u" U
6 N1 i4 B7 u% Y' d- & I; n1 h: E) n6 s5 t; |: C9 U
/ i8 s$ s1 I# X- ?" w- u6 b Size Image : 614400
* d0 d' s3 D$ [4 h) r& {: \- I- d( [( E; y& F- w9 n
- ~4 z1 e# {$ r) z; ~" o% u
+ ^, _. W# Z! c4 r% ~/ V" P
Colorspace : Default9 c7 l$ J# U2 r" }8 B
" c, D8 _8 _1 X' M, P
- 4 S0 M1 M2 b6 Q6 G ?3 ~8 g
2 @0 b* s( z5 ?/ Z Transfer Function : Default3 O6 o: f2 y3 C: w
7 U( d7 G& E3 o1 }( ?4 M" D
7 m' \, W) X1 U( J
2 J/ U$ x0 p5 a0 `! T6 N YCbCr Encoding : Default
: s% b) ?8 a, S1 s) o( A2 f/ x8 d% H1 f& ]6 y: _0 q
- 8 t/ S' }' `1 k- j; X! \3 v9 I9 B3 W
' d) M* Z1 R& M$ ?" F* W+ ]( C
Quantization : Default
* v( i* @4 d( l) a( X
* C: U3 J* Q7 \6 s; A @# Y" \ - 3 f) |8 a( C* N/ x r
, D- T, V0 m7 bCrop Capability Video Capture: n1 y* x! U. ?% E1 ?
: A4 C4 @3 C% o% A& N
- 9 r3 s0 o1 V1 ]. R: u6 Y
: W$ r, u' O* i& H+ X Bounds : Left 0, Top 0, Width 640, Height 480
3 L2 ^' K2 n" V8 f; K4 P' _4 s7 [3 Z( @7 A* u( A# \
- P; B) w, C' E2 V3 M
$ ]/ o& a; {% y. Y. f0 R Default : Left 0, Top 0, Width 640, Height 480
( R [- N( O' E9 z f/ o) x* P- u8 m5 _' D
- % I9 j" u; t( \( L) I5 r" N! Z* z( A
/ J( @0 y2 G& w/ j4 \
Pixel Aspect: 1/1" o+ S( ]2 U. M9 h% G. E
! D3 Z% F% h+ ?2 _; S
- 5 N W2 e j, X2 V1 o( C: P# ~, j
1 I" g3 v$ d3 W4 ^* T" g
Streaming Parameters VideoCapture:
8 x8 Z. K# ?/ N/ b6 B8 }2 o/ k
0 C/ ?, m7 U' c% u0 g
$ F7 R& o5 x3 @% k5 n! c
" F+ F J6 F {' O* o, E- n Capabilities : timepeRFrame ) h( v: u& C1 d' {' S
4 r+ S& a) b$ Z. S' P4 A5 t4 L
- % }# T# c5 {9 ~3 b
6 a+ _5 P# m1 r% O- i$ A k2 L: O
Frames per second: 30.000 (30/1)
# B$ D) S9 ~7 w5 d( e" l" {* E) J; `: z ~
- ; N* L: \- K( k' q
/ B* d4 \* H1 P8 W* U3 e7 N
Read buffers : 0
5 o2 o* I) t8 ?, G7 |3 A3 K
& @: \+ M4 C6 w3 G9 w
( k3 H0 a, j. v" [. D0 Z+ }" d) k3 y+ H
brightness (int) : min=0 max=255 step=1 default=128value=128 & w& B# [ K" Z! W3 M9 P
/ K6 ~' g: |( h, i7 m. J' p. f9 H4 V
8 y$ R) o$ j$ o$ o. N) [' [, D/ p+ e
contrast (int) : min=0 max=255 step=1 default=135value=135
$ `1 W3 D5 {" _- n) Q# x8 w% W: Y( Q+ a/ c. L
# \) b Z( e% t
* l. R$ c0 Z: ~" V7 u saturation (int) : min=0 max=255 step=1 default=75 value=75 ; V- Q! X0 `2 V' s. B4 D z
: g. g; _5 L: F0 D# s% v
; R1 L' r) K3 N$ ]/ c: F* E! T4 r0 N
hue (int) : min=-127 max=127 step=1 default=0 value=0 % m) t' g' l0 n1 s3 L
5 X* l4 c; L4 p, i3 F4 ~
! t/ a" D0 I# d1 Q
: o% T9 b8 B1 c8 k% j gamma (int) : min=1 max=8 step=1 default=4 value=4 1 } Y! ~# l- ?% D% Z
+ F" J7 `! a9 s. i2 h, V+ ?7 N
9 b) S! z' {; o. Y7 p+ p" L9 O
5 ?* v$ d G( t7 ]3 D K7 \: ^6 S1 [power_line_frequency (menu) : min=0 max=2 default=1 value=1
% r1 S* M$ w9 _) }. H Y
! r" t* Y" u3 H5 C/ a8 [- . T6 \$ S7 ~# n, o
0 g, n% ^, }: w7 K9 l |" z. ?sharpness (int) : min=0 max=15 step=1 default=5 value=5& E2 V! T B5 g: a; Q' b+ e8 |
+ N1 Q6 J3 `% S d+ y3 A' C9 [: d
6 v7 f% U; h) c3 ^8 x! \5 G; O. {0 Q! k1 j
backlight_compensation (int) : min=1 max=5 step=1 default=1 value=1
; u, D. S; e+ J" @5 T6 J9 z8 k/ m' ^ \* w6 T
! q0 e( H; V) P3 y/ _
$ J6 g, `* D9 R
我们使用了两种型号的USB摄像头,按照手册说明使用内置的uvccamera程序进行测试,不过都没有成功,得到的错误信息如下图所示。 ![]()
![]()
我们使用FFmpeg可以抓取视频,命令行如下: ffmpeg -f video4linux2 -s 640x480 -pix_fmt yuyv422 -i /dev/video0 out.yuv& P. R, ^% s$ S
使用Windows版本的ffplay可以正常播放抓取的视频,命令行如下: ffplay -s 640x480 -pix_fmt yuyv422 out.yuv8 B1 y! S" K6 e1 M/ u5 E
上面保存的是YUV格式的原始视频,如果要保存压缩视频,可以用下面的命令行: - " I' a7 D1 A" O/ C, u+ v4 O
ffmpeg -y -t 15 -r 25 -f video4linux2 -i /dev/video0 out3.mp4-timestamps bs
+ @+ H3 C- F" P' q _! j9 v其中的-r 25表示每秒采样25帧,这个参数必须有,否则FFmpeg可能会不断地采集并压缩同一视频帧。-r参数超过30没有什么意义,因为USB摄像头的最大能力就是30fps。
( l) f% U0 P; V* B飞凌嵌入式OKA40i-C开发板可以对于1080P的视频压缩达到45fps,所以对USB摄像头的视频压缩应该没有什么压力。 ' \# i9 U2 _* |8 |- s/ x
3. FFmpeg性能测试 FFmpeg有个benchmark参数可以方便进行性能测试。我们对A40i开发板自带的一个MP4视频就行解码测试,命令行如下: - / F' u7 |/ d! l: }# Z8 k. n
ffmpeg-benchmark -i translate.mp4 -f null –
$ d8 R8 R4 H* H; C. K8 c, S' a6 i得到的测试数据如下: - 7 F# R' m6 h% y J& _
3 I- S( W) B0 n Q" \
video:6 t' C0 M6 I }, ?+ C# \
# `- Y$ K# W* U$ e
- % U; Q1 W' N& S
# }$ B8 G, }" ^1 H! C, y148kB' s+ }1 A+ ?& M5 J: T3 i) C
, |# J2 T l K; X" }. {
% f# Z' P ^. f: d! q) {8 y# t2 p) Q3 `7 S& k- R
audio:
% j: ^5 ]1 H$ k. c2 z' d$ R) W
; z( |( c" S7 [5 j5 U! t4 A, t4 _8 P
5 o; D; {- K% _! u3 H, y
; O& C0 e3 l; x- P7 P6 m+ \. c3428kB subtitle:0kB other streams:0kB globalheaders:0kB muxing' z! T i- X7 I" p: c! }/ U; A( A- e
8 F- V& q# m N2 ^9 C
- . V, h7 j6 I% p, k+ \; ~" F
' C- t7 q3 v& g' Foverhead:
( x! o5 J, t4 o+ w# ^5 a* S
7 R) |, K; p9 O" F7 J5 A( ?
P6 f: x, `2 i& U5 B4 Z
% p' J5 X0 U# C+ R2 k" Cunknown
( r6 \% z4 U G- Q4 S% z" Q/ R( v* ~* }& k* Y
0 m$ Z+ V1 [/ `, v5 h% j$ F( L
X- x! g8 Y3 M0 obench:! A; f6 N4 n' G/ W" L
" ? i% p% A# a. e. K; K, o+ I( L
8 q4 Y, z8 x9 N7 m; f
7 F: \! M. p, G4 L. T* Y) T% Xutime=2.820s stime=0.110s rtime=0.956s& F5 b, m- n% P9 S6 E
/ ^; H4 w' j# K. ~8 o; t
& H5 f3 \9 _0 {$ v# {7 X4 j* c
- m" U/ V# D* i. Mbench:
" H! e1 m" E+ [
, [/ H" `! b, L3 w5 a2 a
' _/ g: L' T. f- _# c% h6 Y. ]! n& n$ T2 w/ ?8 D0 H- y- w
maxrss=14208kB
& F6 @. m- d3 v: g; g: v" I/ T9 M' O, y
! | U/ W+ n. V5 e0 K3 a) C ! L( L$ w% T: a5 J; Z
由于我手上暂时没有其他的开发板可以对比,于是就通过我用了5年的i7-6500笔记本测试了一下,测试结果如下:
# @5 l, [" W) ]+ J) W2 W [/ N) e a8 Q
video:
( ^4 s. e' Z3 j% V4 D/ @; y4 j& C
- . H- i( A* D [; K
8 A; q5 s: T' w3 i: [241kB% B N; {# v/ Z" l; i8 H
, y: d6 N# ]' R. `# K
- 2 ?8 W! v* G. O. A
$ X) r7 u8 x3 C; |audio:
' q5 t1 {3 k) C6 x# ]- L F/ ]+ F+ G. ]' U h+ F6 O) h
- $ @" X9 l" ` \, v; M% B
# C3 M4 N1 S& r" }
3428kB subtitle:0kB other streams:0kB globalheaders:0kB muxing$ @" y1 W4 S4 b$ I
5 ]% R" u1 `" U* j$ V7 Z; I' d3 l
# o! J. N: c5 S: s: V) G/ B& S% J& c0 l; _& X: K
overhead: . P9 Q: M1 `" b' G5 ^
/ l+ {0 o9 E$ k# O$ X& \4 @2 ~- * Z: L, `5 r* ~7 I, D8 Y. V
, m$ P D( d7 tunknown% |& j9 i( h/ l/ x! p+ A* y
5 U5 B* d1 s- C3 b. N3 P
6 p6 j8 d7 c: _5 p, w+ |. Z; u1 s/ w9 i U. R N/ P
bench:: t, k1 g7 i3 u8 C. c9 z
) m) E. |! c8 V, W- - U, @1 x# H5 l
! L+ o5 E! _ z0 \
utime=0.391s stime=0.000s rtime=0.228s0 T: A+ f3 Q' G% b8 u
8 E, n y7 b# c+ c - ! x4 T3 _5 }, ^
9 }/ |9 i; \. {
bench:- q% m; q( p6 Q# f% a0 L
3 K( A0 Z; U6 z4 w
! K3 b6 L9 Z2 D& ]- c
5 ]$ c; B5 f# S$ Zmaxrss=20316kB8 f' @0 H- Z# N& M. k
& _: |( f1 Q9 N5 m
7 k1 I y& M# Q% U: D
% T; ]9 f) x% E) G9 M3 t4. FFmpeg产生实时视频流 FFmpeg可以支持实时视频流的发送和接收,从而可以把OKA40i-C开发板上的视频实时发送到PC上,由PC上的软件实时接收并显示。我们可以使用下面的命令将OKA40i-C开发板上的一个MP4转换为RTP码流发送的PC上: - " T9 O3 y; r1 F' u) l2 C, g1 w
ffmpeg -re -i test.mp4 -an -c copy -f rtp rtp://192.168.0.105:12340 g! l1 C7 G; }& l% v/ H, U
使用Wireshark可以看到在PC机的1234端口收到大量来自OKA40i-C开发板的H.264视频流。 ![]()
6 a V1 a0 D% q& U
) `$ E p5 x, H# v. w- h5 n如果想在PC上显示视频流,需要建立一个SDP文件,它描述视频流中的端口和编码信息。 , ?( S# ^7 q& c: P
SDP是来自SIP标准中定义,目前VLC、Apple QuickTime和ffplay等很多软件都可以打开SDP文件,并按照SDP中的描述显示视频流。SDP文件并不需要手工编写,在ffmpeg运行时它会显示命令行所对应的SDP定义,如下图所示。 ![]()
也可以用重定向将输出写入一个SDP文件,如: ffmpeg -re -i test.mp4 -an -c copy -f rtp rtp://192.168.0.105:1234 > rtp.sdp
/ u7 W0 v. i L, l; x. W下面就是使用VLC显示的接收到的视频流。 ![]()
5 [! U( Y9 I- R% E6 n) m
$ g ?5 A, T# ?" b* L) R* ~5. FFmpeg转发USB摄像头的视频流 前面演示了将MP4文件转换为视频流,我们也可以将USB摄像头采集的内容实时转发到PC上,使用下面的命令行即可。 ffmpeg -y -t 15 -r 25 -f video4linux2 -i /dev/video0 -f rtprtp://192.168.0.105:1234 > usb.sdp! ?+ m; ^9 i$ U8 l* t! M) o
|