Jonasen 发表于 2021-7-21 12:34

php无人值守录制抖音直播

>为了家中老人,老人有的时候不在家,关注的主播直播内容就容易错过,用python是可以录制,但是家中老人还不会弄电脑,就衍生了这个项目-_-!

# 原理

1. 安装ffmpeg
2. php解析抖音直播地址
3. php调用ffmpeg将转换过来的直播地址进行录制
4. 添加定时任务,定时调用脚本

# 安装ffmpeg

我的环境是centos7.x,先更新下yum,采用yum的方式进行安装ffmpeg,先更新下当前yum

```shell
yum -y update
```

安装Nux Dextop Yum 源**(慎重操作)**

```shell
sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
```

安装FFmpeg 和 FFmpeg开发包

```shell
sudo yum install ffmpeg ffmpeg-devel -y
```

测试ffmpeg是否成功安装

```shell
ffmpeg
```

*这里补充下,我的环境是宝塔环境,宝塔之前的一键包安装ffmpeg已经失效了,问题很多,在这里不建议大家采用宝塔的一键包,我现在的安装方案是采用宝塔论坛 `CentOS7宝塔面板安装ffmpeg视频切片模块``yaojiu`的安装方式。

# 解析抖音直播地址

这里的抖音直播源解析是通过我前一段时间写的`php抖音直播源抓取`进行的解析,原理就是所有的信息都在 `window.__INIT_PROPS__`这个部分当中,而这部分内容是json结构的,所以我们只要将这部分代码转为能够读取的json然后进行调用就可以,需要的小伙伴自行观看。
这里放上thinkphp抓取抖音直播源的源码:
```php
<?php
/****抖音直播解析接口*******/
namespace app\controller;
use app\BaseController;
use think\facade\Request;

class Douyin extends BaseController
{
        public function index(){
                $url=Request::param('url');
                $html=$this->get_douyin($url);
                preg_match_all('/window.__INIT_PROPS__ =(.*)<\/script><\/head>/', $html, $jsmatch);
                if(!empty($jsmatch)){
                        $content=json_decode($jsmatch,1);
                        if(!empty($content['/webcast/reflow/:id']['room']['stream_url']['hls_pull_url'])){
                                $data=array(
                                        'code'=>200,
                                        'success'=>true,
                                        'data'=>array(
                                                'url'=>$content['/webcast/reflow/:id']['room']['stream_url']['hls_pull_url'],
                                                'title'=>$content['/webcast/reflow/:id']['room']['title'],
                                                'id'=>$content['/webcast/reflow/:id']['room']['id'],
                                                'status'=>$content['/webcast/reflow/:id']['room']['status']
                                        )
                                );
                                echo json_encode($data);
                        }else{
                                $data=array(
                                        'code'=>400,
                                        'success'=>false,
                                        'msg'=>'数据接口请求失败'
                                );
                                echo json_encode($data);
                        }
                }
        }
        privateget_douyin($url,$post='',$cookie='', $returnCookie=0,$header=array(),$referer=''){
                $curl = curl_init();
                if(!empty($header)){
                        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
                        curl_setopt($curl, CURLOPT_HEADER, 0);//返回response头部信息
                }
                curl_setopt($curl, CURLOPT_URL, $url);
                curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 跳过证书验证(https)的网站无法跳过,会报错
      curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书验证
                curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; Nexus 6P Build/OPM7.181205.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.11.1.1197 Mobile Safari/537.36');
                curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
                curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
                curl_setopt($curl, CURLOPT_REFERER, $referer);
                if($post) {
                        curl_setopt($curl, CURLOPT_POST, 1);
                        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
                }
                if($cookie) {
                        curl_setopt($curl, CURLOPT_COOKIE, $cookie);
                }
                curl_setopt($curl, CURLOPT_HEADER, $returnCookie);
                curl_setopt($curl, CURLOPT_TIMEOUT, 10);
                curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
                $data = curl_exec($curl);
                if (curl_errno($curl)) {
                        return curl_error($curl);
                }
                curl_close($curl);
                if($returnCookie){
                        list($header, $body) = explode("\r\n\r\n", $data, 2);
                        preg_match_all("/Set\-Cookie:([^;]*);/", $header, $matches);
                        $info['cookie']= substr($matches, 1);
                        $info['content'] = $body;
                        return $info;
                }else{
                        return $data;
                }

}
}
```


传递回来的参数为:

```json

{"code":200,"success":true,"data":{"url":"http:\/\/pull-hls-l6.douyincdn.com\/stage\/stream-685625243370782751_or4\/index.m3u8","title":"jonasen\u6b63\u5728\u76f4\u64ad","id":6986527143291637000,"status":2}}
```

# php调用ffmpeg进行录制

php如果直接调用ffmpeg是不行的,我们需要执行proc_open,proc_get_status,proc_close命令,所以要将php.ini中对应的命令启用。

我这里做了个自动判断直播状态,传递回来的参数中如果status不等于2的情况下,代表当前录播已经停止,所以执行一次停止直播的命令,虽然ffmpeg在抖音关播以后会自动停止(亲测),但是保险期间还是做了一个容错。

以下是我用thinkphp5测试过后的代码:

```php
<?php
/****抖音直播录制接口*******/
namespace app\controller;
use app\BaseController;
use think\facade\Request;
class Live extends BaseController
{
        public function index(){
                $url=Request::param('url');
                $status=Request::param('status');//停止录播传个任意参数
                $apiUrl="http://xx/Douyin?url=".$url;//获取抖音直播的接口,见本博客
                $returnData=file_get_contents($apiUrl);
                $data=json_decode($returnData,true);
                if($data['code']==200){
                        if($data['data']['status']==2){
                                if(!empty($status)){
                                        if(!file_exists($data['data']['id'].".txt")){
                                                echo "当前直播不存在";
                                                die();
                                        }
                                        $pid=file_get_contents($data['data']['id'].".txt");
                                        proc_close(proc_open('kill -9 '.$pid, array(), $pipes));//杀死进程
                                        unlink($data['data']['id'].".txt");
                                        echo "已停止录播";
                                        exit();
                                }
                                //判断当前直播是否正在录屏中
                                if(file_exists($data['data']['id'].".txt")){
                                        echo "当前直播正在进行中";
                                        die();
                                }
                                //直播正在进行中
                                $command="ffmpeg -i ".$data['data']['url']." -c copy -bsf:a aac_adtstoasc -f mp4 /www/wwwroot/当前网站路径/public/upload/".$data['data']['id'].".mp4 >/dev/null 2>&1 &";
                                $process = proc_open($command, array(),$pipes); //执行录屏命令
                                $var = proc_get_status($process); //获取命令进程信息
                                $pid = intval($var['pid'])+1;//pid就是进程ID,$var['pid']得到的ID比实际的少1
                                $pidFile = fopen($data['data']['id'].".txt", "w+");//创建当前任务信息文档
                                fwrite($pidFile, $pid);
                                fclose($pidFile);
                                echo "正在录播";
                        }else{
                                $pid=file_get_contents($data['data']['id'].".txt");
                                proc_close(proc_open('kill -9 '.$pid, array(), $pipes));//杀死进程
                                unlink($data['data']['id'].".txt");
                                echo "已停止录播";
                                exit();
                                //结束
                                echo "直播已经结束";
                        }
                }else{
                        echo "未获取到直播信息";
                }
        }

}
```

# 计划任务

在宝塔中添加定时任务,访问地址为:

![请输入图片描述](https://www.jonasen.cn/usr/uploads/2021/07/149438287.png)

# 相关网址

开始直播:
http://xxx.cn/Live?url=https://v.douyin.com/et3Nt53/

结束直播:
http://xxx.cn/Live?url=https://v.douyin.com/et3Nt53/&status=1

Jonasen 发表于 2021-7-21 14:33

这里需要补充下,使用该脚本,可以同时录播多个直播。

onemores 发表于 2022-3-14 23:44

题主有个问题期待回复就是怎么同时录制多个直播呢,开一个ffmpeg录制CPU就已经跑满了   两个ffmpeg进程电脑基本跑不动了? 这个怎么解决呢?

piazini 发表于 2022-1-6 21:25

wzyl 发表于 2021-7-21 13:58
php果然是世界上最好的编程语言赞一个

最好的编程语言,为啥这么说?

3300452914 发表于 2021-7-21 13:25

谢谢大佬

mafeng123 发表于 2021-7-21 13:37

厉害厉害,这个6.省一大堆事

QQ_2C5943 发表于 2021-7-21 13:38

谢谢大佬

shuiaohuaheng 发表于 2021-7-21 13:43

厉害厉害。。试一下效果

www805 发表于 2021-7-21 13:47

相当牛逼。

lyjsolo 发表于 2021-7-21 13:47

谢谢分享!学习了

隔壁小赖 发表于 2021-7-21 13:49


谢谢大佬分享

wzyl 发表于 2021-7-21 13:58

php果然是世界上最好的编程语言赞一个 :lol

katitus 发表于 2021-7-21 14:05

太牛逼了!!!
页: [1] 2 3
查看完整版本: php无人值守录制抖音直播