---
author: Calvinlin
category: 技术
comments_data:
- date: '2022-03-09 11:45:01'
  message: 太卷了，坐等幼儿园大班的儿童投稿
  postip: 61.145.82.10
  username: 来自广东佛山的 Chrome Mobile 75.0|Android 10 用户
- date: '2022-03-09 11:49:33'
  message: 作者在此
  postip: 119.139.193.99
  username: 来自广东深圳的 Firefox 98.0|Android 11 用户
- date: '2022-03-09 16:11:36'
  message: "一个小建议。<br />\r\n<br />\r\n使用 pip install 安装库时，加上 --user 参数 (即: pip install
    --user)，会将其安装到当前用户目录中 (位于 ~/.local)，<br />\r\n不加的话，会安装到系统目录 (位于 /usr)，会有什么后果呢？<br
    />\r\n<br />\r\n+ pip 卸载时不支持卸载依赖，会导致系统中残留文件越来越多<br />\r\n+ 可能会覆盖系统中已有的文件，造成部分
    Python 程序无法正常运行<br />\r\n+ 使用系统包管理器 (如 apt、pacman...) 安装、升级软件包时可能会出错"
  postip: 117.177.31.1
  username: 来自四川自贡的 Chrome 85.0|Mac 10.16 用户
- date: '2022-03-09 16:19:46'
  message: "如果想要把 Python 库装到系统目录，建议为对应的发行版打包，然后用发行版的包管理器进行管理。<br />\r\n<br />\r\n比如
    Arch Linux 系统打 Python 包指南：<br />\r\nwiki.archlinux.org/title/Python_package_guidelines"
  postip: 117.177.31.1
  username: 来自四川自贡的 Chrome 85.0|Mac 10.16 用户
- date: '2022-03-09 16:37:25'
  message: '666666'
  postip: 121.228.37.136
  username: 来自江苏苏州的 Chrome 97.0|GNU/Linux 用户
- date: '2022-03-09 17:32:32'
  message: 一般不用root用户安装的时候 是默认.local的 因为/usr普通用户不可写
  postip: 183.46.88.11
  username: 来自广东汕头的 Firefox 98.0|Android 11 用户
- date: '2022-03-09 18:01:25'
  message: 顺手加上是个好习惯，保不齐哪天用到 ROOT 用户忘了加。
  postip: 117.177.31.1
  username: 来自四川自贡的 Chrome 85.0|Mac 10.16 用户
- date: '2022-03-09 18:50:43'
  message: 在 Arch Linux 社区里见过太多一言不合就 sudo pip 的了，然后包管理器 (pacman) 也跟着出问题。
  postip: 117.177.31.1
  username: 来自四川自贡的 Chrome 85.0|Mac 10.16 用户
count:
  commentnum: 8
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 7546
date: '2022-03-09 11:00:00'
editorchoice: false
excerpt: 我用 Python + FFmpeg  + DLNA 完成了一个在 Linux 下的投屏方案。
fromurl: https://github.com/LCTT/Articles/pull/2
id: 14341
islctt: false
largepic: /images/p/202203/09/105914jtdf11egqu6p15tu.jpg
permalink: /article-14341-1.html
pic: /images/p/202203/09/105914jtdf11egqu6p15tu.jpg.thumb.jpg
related: []
reviewer: wxy
selector: ''
summary: 我用 Python + FFmpeg  + DLNA 完成了一个在 Linux 下的投屏方案。
tags:
- DLNA
- 投屏
thumb: false
title: 如何在 Linux 下使用 DLNA 投屏
titlepic: true
translator: ''
updated: '2022-03-09 11:00:00'
---

![](/images/p/202203/09/105914jtdf11egqu6p15tu.jpg)



> 
> 编者按：本文系 Linux 中国公开投稿计划所接受的第一篇投稿，而且投稿作者是一位初中学生，让我们为他点赞！
> 
> 
> 


一般来说，安卓设备和 Windows 设备投屏使用的是 miracast 协议，但是该协议要求网卡支持 p2pwifi，而 Linux 下大多数网卡驱动不支持 p2pwifi。


于是我用 Python + FFmpeg + DLNA 完成了一个在 Linux 下的投屏方案。这个方案的不足是延迟有点大。


### 设置


下面是如何实现。


先装这个 DLNA 库：



```
pip3 install dlna

```

然后用 `pactl` 查找 “监视器信源”（中文输出） 或 “Monitor Source”（英文输出）：



```
pactl list sinks

```

示例输出：



```
Sink #0
	State: RUNNING
	Name: alsa_output.pci-0000_05_00.6.HiFi__hw_Generic_1__sink
	Description: Family 17h (Models 10h-1fh) HD Audio Controller Speaker + Headphones
	Driver: module-alsa-card.c
	Sample Specification: s16le 2ch 44100Hz
	Channel Map: front-left,front-right
	Owner Module: 9
	Mute: no
	Volume: front-left: 53814 /  82% / -5.14 dB,   front-right: 53814 /  82% / -5.14 dB
	        balance 0.00
	Base Volume: 65536 / 100% / 0.00 dB
	Monitor Source: alsa_output.pci-0000_05_00.6.HiFi__hw_Generic_1__sink.monitor
	Latency: 16676 usec, configured 16000 us...

```

然后创建一个 CGI 脚本 `screen.flv`。首先。建立放置该脚本的目录：



```
mkdir screencast
mkdir screencast/cgi-bin

```

然后通过 `cat` 来直接创建该脚本：



```
cat <<eof>screencast/cgi-bin/screen.flv
#!/bin/bash
echo "Content-Type:video/x-flv"
echo

ffmpeg -f pulse -i <监视器信源>   -f x11grab -i :0  -vcodec h264_nvenc  pipe:.flv
eof

```

请用上面获得的监视器信源替换文件中的 `<监视器信源>`。


并为它设置可执行权限：



```
chmod +x screencast/cgi-bin/screen.flv 

```

注意：如果没有 Nvidia 显卡，或者要使用其他的硬件加速，请把编码方案 `h264_nvenc` 替换为相应的编码方案。不建议采用软解方式，延迟非常高。


### 投屏


需要投屏时，首先启动本地 Web 服务器：



```
cd screencast
python3 -m http.server --cgi 9999&

```

然后，找到你的 DLNA 设备，然后把 `location` 后面的 URL 复制下来：



```
dlna device

```

示例输出：



```
=> Device 1:
{
    "location": "http://192.168.3.118:1528/",
    "host": "192.168.3.118",
    "friendly_name": "Kodi",
...

```

找到你的 Linux 电脑的局域网 IP 地址：



```
ip addr

```

示例输出：



```
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 74:4c:a1:82:2e:3f brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.117/24 brd 192.168.3.255 scope global dynamic noprefixroute wlp2s0
       valid_lft 58283sec preferred_lft 58283sec
    inet6 240e:3b3:2ee3:9530:d005:e492:6243:9/128 scope global dynamic noprefixroute 
       valid_lft 6738sec preferred_lft 3138sec
    inet6 240e:3b3:2ee3:9539:f289:6043:c56a:4e7b/64 scope global dynamic noprefixroute 
       valid_lft 7189sec preferred_lft 3589sec
    inet6 240e:3b3:2ee3:9539:3714:eaf0:c549:b8c9/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 7188sec preferred_lft 3588sec
    inet6 fe80::c746:2540:ab7b:20aa/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 fe80::3543:2637:e0fc:3630/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

```

启动投屏的命令如下：



```
dlna play -d <URL> http://<局域网 IP>:9999/cgi-bin/screen.flv

```

请相应替换其中的 `<URL>` 和 `<局域网 IP>` 参数，此处我替换后的命令是：



```
dlna play -d http://192.168.3.118:1528/ http://192.168.3.117:9999/cgi-bin/screen.flv

```

然后在你的电视上设置接受投屏，各种电视设备设置投屏方式不同，请参照具体设备说明。


稍等片刻，视频就会出现在电视上了。投屏效果如下：


![](/images/p/202203/09/105924fhgh0z00k0930sc9.jpg)




---


作者简介：


calvinlin：一个普通的深圳初中生。




---


via: <https://www.bilibili.com/read/cv15488839>


作者：[calvinlin](https://space.bilibili.com/525982547) 编辑：[wxy](https://github.com/wxy)


本文由贡献者投稿至 [Linux 中国公开投稿计划](https://github.com/LCTT/Articles/)，采用 [CC-BY-SA 协议](https://creativecommons.org/licenses/by-sa/4.0/deed.zh) 发布，[Linux中国](https://linux.cn/) 荣誉推出