树莓派实现24小时直播点歌功能
本文最后更新于 2779 天前,其中的信息可能已经有所发展或是发生改变。

此文章已经十分久远,请直接去看
【重写】树莓派驱动的b站点播台

【重写】树莓派驱动的b站点播台


最新的文章已经把代码更新为弹幕点歌了,并且在GitHub持续更新。

在这篇文章发布之前,我在it水家已经投过一稿了:http://www.ithome.com/html/win10/311694.htm

另外上一篇不带点歌功能,只有推流功能的教程:https://www.chenxublog.com/2017/06/02/raspi-live-24h-bilibili.html

如果是零基础,建议先看一遍上面那两篇文章,如果是使用代码,请参考本文。这几天代码已经更新多次。

我写的代码只能保证可用,毕竟我是业余的233333欢迎大神拿我的思路进行优化

github:https://github.com/chenxuuu/24h-raspberry-live-on-bilibili

php端运行的代码(最后更新于2017.6.4晚):

<head>
<meta charset="utf-8">
</head>
<body>
<form action="" method="post">
<p>一个简陋的点歌台23333</p>
<p>搜索结果来自网易云</p>
<p>输入歌曲名搜索歌曲:<input type="text" name="song" /></p>
<p><input type="submit" name="sub" value="搜索" /></p>
</form>
<form action="" method="post">
<p>或者直接输入id点歌(推荐!)<br/>实例(红色部分为id):<br/>http://music.163.com/song/<font color="red">26489014</font>/?userid=261620056<br/>http://music.163.com/#/song?id=<font color="red">32477053</font></p>
<p>id:<input type="text" name="id" /></p>
<p><input type="submit" name="sub" value="查看" /></p>
</form>
by 晨旭/chenxublog.com | running on Raspberry Pi 2 Model B<br/>直播间地址:http://live.bilibili.com/16703<br/><br/><br/>
当前状态:<div id='t'></div>
<?php
require_once 'NeteaseMusicAPI_mini.php';

function get_url_id($id)
{
    $api = new NeteaseMusicAPI();
    $result = $api->url($id);
    $result = str_replace("[","",$result);
    $result = str_replace("]","",$result);
    $data=json_decode($result, true);
    return $data['data']['url'];
}
function urlcheck($url)
{
    $counttemp=0;
    for($counttemp=1;$counttemp<31;$counttemp++)
    {
        if (file_exists($counttemp.'.txt') && $url==file_get_contents($counttemp.'.txt'))   
        {   
            return false;
        }
    }
    return true;
}
function netease_http($url)
{
    $refer = "http://music.163.com/";
    $header[] = "Cookie: " . "appver=1.5.0.75771;";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
    curl_setopt($ch, CURLOPT_REFERER, $refer);
    $cexecute = curl_exec($ch);
    curl_close($ch);
    if ($cexecute)
    {
        $result = json_decode($cexecute, true);
        return $result;
    }
    else
    {
        return false;
    }
}
function getStatus($url){
    if($headers = @get_headers($url)){
            $status  = $headers[0];
            $statusno= false;
            if(preg_match_all('%HTTP/1\.1 ([\d]{3})%i',$status,$matches)){
                    $statusno = $matches[1][0];
            }
            return $statusno;
    }
        return false;
}

if(!empty($_POST['song'])){

$song=$_POST['song'];
echo '搜索关键词:'.$song.'<br/>=========================================================<br/>';
$url = "http://s.music.163.com/search/get/?type=1&s=".$song;
$response = netease_http($url);
$counttemp=0;
for($counttemp=0;$counttemp<10;$counttemp++)
{
    if(getStatus($response['result']['songs'][$counttemp]['audio'])=='200')
    {
        echo $response['result']['songs'][$counttemp]['name'].'<img src="'.$response['result']['songs'][$counttemp]['album']['picUrl'].'" height="100"/><a href="?down='.$response['result']['songs'][$counttemp]['audio'].'">就选这首了</a><br/>试听:<audio src="'.$response['result']['songs'][$counttemp]['audio'].'" controls="controls"></audio><br/>=========================================================<br/>';
    }
    else
    {
        echo '第'.($counttemp+1).'首歌曲获取失败(歌曲失效/版权问题/网络抽风)<br/>=========================================================<br/>';
    }
}

}
elseif(!empty($_POST['id'])){
    echo '试听:<audio src="'.get_url_id($_POST['id']).'" controls="controls"></audio><br/><a href="?down='.get_url_id($_POST['id']).'">就选这首了</a>';
}
elseif(!empty($_GET['down']) && empty($_GET['write']) && strpos($_GET['down'],"music.126.net")!=false && getStatus($_GET['down'])=='200')
{
    echo '当前可供选择的空闲的序列(注意,直播是从第1首到第30首按顺序播放的。歌曲长度最大限制六分钟,超过将丢弃。):<br/>';
    $counttemp=0;
    for($counttemp=1;$counttemp<31;$counttemp++)
    {
        if($counttemp%5==0)
        {
            echo '<br/>';
        }
        if (!file_exists($counttemp.'.txt'))
        {
            echo '<a href="?write='.$counttemp.'&down='.$_GET['down'].'">换掉第'.$counttemp.'首歌</a>(<font color="green">可以换歌</font>)|';
        }
        else
        {
            echo '第'.$counttemp.'首歌(<font color="red">排队渲染中</font>)|';
        }
    }
}
elseif(!empty($_GET['write']) && !empty($_GET['down']) && urlcheck($_GET['down']) && getStatus($_GET['down'])=='200')
{
    if(!file_exists($_GET['write'].'.txt'))
    {
        //file_put_contents('songs/'.$_GET['write'].'.txt', $_GET['down']);
        $myfile = fopen($_GET['write'].'.txt', "w") or die("Unable to open file!");
        fwrite($myfile, $_GET['down']);
        fclose($myfile);
        echo '第'.$_GET['write'].'首歌曲的渲染请求提交成功!<a href="index.php">返回首页</a>';
    }
    else
    {
        echo '啊哦!这个序号已经有人选中了!正在渲染!';
    }
}
else
{
    echo '树莓当前负载状态(注意,直播是从第1首到第30首按顺序播放的):<br/>';
    $counttemp=0;
    for($counttemp=1;$counttemp<31;$counttemp++)
    {
        if($counttemp%5==0)
        {
            echo '<br/>';
        }
        if (!file_exists($counttemp.'.txt'))
        {
            echo '第'.$counttemp.'首歌(<font color="green">可以换掉</font>)|';
        }
        else
        {
            echo '第'.$counttemp.'首歌(<font color="red">排队渲染中</font>)|';
        }
    }
}

?>
<script type="text/javascript" src="now.js"></script>
</body>

同目录下需要新建一个NeteaseMusicAPI_mini.php,文件取自:

https://github.com/metowolf/NeteaseCloudMusicApi/blob/master/weapi/NeteaseMusicAPI_mini.php

php文件我全部放到了/usr/share/nginx/www/songs目录下。

渲染处理部分:

ff.py(路径/home/pi/songs/)

# -*- coding:utf-8 -*-
import os
import urllib
import eyed3
import time
for i in range(1, 30+1):
  if(os.path.exists(str(i)+'.mp3')):
    os.remove(str(i)+'.mp3')
    os.remove('/usr/share/nginx/www/songs/'+str(i)+'.txt')
  if(os.path.exists('/usr/share/nginx/www/songs/'+str(i)+'.txt')):
    f = open('/usr/share/nginx/www/songs/'+str(i)+'.txt')
    content = f.read()
    fileout = file('/usr/share/nginx/www/songs/now.js','w')
    fileout.write('t.innerHTML=("正在下载'+str(i)+'.mp3")')
    fileout.close()
    urllib.urlretrieve(content, str(i)+'.mp3')
    print('download success')
    xx=eyed3.load(str(i)+'.mp3')
    seconds=xx.info.time_secs
    if(seconds<600):
      fileout = file('/usr/share/nginx/www/songs/now.js','w')
      fileout.write('t.innerHTML=("正在生成'+str(i)+'.mp4的一图流视频 第一步/共两步")')
      fileout.close()
      os.system('ffmpeg -loop 1 -r 1 -t '+str(seconds)+' -f image2 -i '+str(i)+'.png -vcodec libx264 -pix_fmt yuv420p -crf 24 -y SinglePictureVideo.mp4')
      fileout = file('/usr/share/nginx/www/songs/now.js','w')
      fileout.write('t.innerHTML=("正在将'+str(i)+'.flv的视频与音频合为一体 第二步/共两步")')
      fileout.close()
      os.system('ffmpeg -i SinglePictureVideo.mp4 -i '+str(i)+'.mp3 -c:v copy -c:a aac -y '+str(i)+'.flv')
      os.remove(str(i)+'.mp3')
      os.remove('SinglePictureVideo.mp4')
      os.remove('/usr/share/nginx/www/songs/'+str(i)+'.txt')
      fileout = file('/usr/share/nginx/www/songs/now.js','w')
      fileout.write('t.innerHTML=("成功渲染'+str(i)+'.flv!60秒后会开始渲染下一个视频")')
      fileout.close()
    else:
      os.remove(str(i)+'.mp3')
      os.remove('/usr/share/nginx/www/songs/'+str(i)+'.txt')
    time.sleep(60)
time.sleep(10)

ff.sh(路径/home/pi/songs/)

#!/bin/bash
while true
do
 python ff.py
done

路径/home/pi/songs/下还有1-30.png文件用于作为视频内容

启动ffmpeg部分:

playlist.txt请自己写吧,规则见https://trac.ffmpeg.org/wiki/Concatenate

live.sh(与playlist.txt同级)

#!/bin/bash
while true
do
  ffmpeg -re -f concat -safe 0 -i playlist.txt -vcodec copy -acodec aac -b:a 192k -f flv "你的直播地址和码"
done

理论上到这里就结束了,但是网络老断,那我只能暴力检测和强制重启推流来解决了

断网自动重推部分:

net.py

#coding:utf8
'''python3 code
author's email: [email protected]
通过统计ifconfig命令的输出,计算当前网速
'''

import logging
logging.basicConfig(level=logging.INFO,
                format='%(message)s',
                #filename='speed',
                #filemod='w'
                )

import os, sys, time
import re

def get_total_tx_bytes(interface, isCN):
    grep = '发送字节' if isCN else '"TX bytes"'
    r = os.popen('ifconfig '+interface+' | grep '+grep).read()
    total_bytes = re.sub('(.+:)| \(.+','',r)
    return int(total_bytes)

def get_total_rx_bytes(interface, isCN):
    grep = '接收字节' if isCN else '"RX bytes"'
    r = os.popen('ifconfig '+interface+' | grep '+grep).read()
    total_bytes = re.sub(' \(.+','',r)
    total_bytes = re.sub('.+?:','',total_bytes)
    return int(total_bytes)


if __name__=='__main__':
    interface = sys.argv[1]
    get_total_bytes = get_total_tx_bytes if sys.argv[2]=='tx' else get_total_rx_bytes
    isCN = True if sys.argv[3]=='cn' else False
    freq = int(sys.argv[4])
    low_count = 0
    for i in range(1, 10 + 1):
        last = get_total_bytes(interface, isCN)
        time.sleep(freq)
        increase = get_total_bytes(interface, isCN) - last
        logging.info(str(increase/freq/1000))
        speed_now = increase/freq/1000
        if(speed_now < 5):
            low_count = low_count +1
    if(low_count > 5):
        os.system('killall ffmpeg')
        time.sleep(1)
        os.system('killall ffmpeg')
        time.sleep(1)
        os.system('killall ffmpeg')
        logging.info('666')
    else:
        logging.info('ok!')

net.sh

#!/bin/bash
while true
do
python net.py eth0 tx false 1
done

这样所有我用的脚本都贴在这里了,启动方式就是扔几个screen就行了

screen sh live.sh
#按ctrl+a,ctrl+d
screen sh net.sh
#按ctrl+a,ctrl+d
cd songs/
screen sh ff.sh
#按ctrl+a,ctrl+d

完毕~

技术不高,如有错误,请指出,谢谢o( ̄▽ ̄)ブ

评论

  1. 8 年前
    2017-6-05 14:41:57
    Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Windows 10 x64 Edition Windows 10 x64 Edition

    好厉害,不过我没有树莓派,用VPS搭建可以吗?

    • 博主
      Clarke
      8 年前
      2017-6-05 15:17:58
      Google Chrome 60.0.3107.4 Google Chrome 60.0.3107.4 Windows 10 x64 Edition Windows 10 x64 Edition

      理论上应该也是可行的,你可以试试

      • 晨旭
        8 年前
        2017-6-05 21:32:39
        Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Windows 10 x64 Edition Windows 10 x64 Edition

        呃,ffmpeg编译不成功,想问问博主的树莓派装的是什么系统呢?

        • 博主
          Clarke
          8 年前
          2017-6-05 22:10:24
          Google Chrome 60.0.3107.4 Google Chrome 60.0.3107.4 Windows 10 x64 Edition Windows 10 x64 Edition

          试试yum或者apt-get看看有没有?
          树莓系统是基于debian的raspbian,ubuntu之类的都是基于debian

          • 晨旭
            8 年前
            2017-6-06 11:34:31
            Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Windows 10 x64 Edition Windows 10 x64 Edition

            我换了很多个系统,Debian和Ubuntu都用过了,就是在安装解码器时执行
            ./configure –host=arm-unknown-linux-gnueabi –enable-static –disable-opencl
            会提示No working C compiler found.,我谷歌了也找不到有效的解决方法,请问你有没有遇到这种情况?

            • 博主
              Clarke
              8 年前
              2017-6-06 11:37:25
              Google Chrome 60.0.3107.4 Google Chrome 60.0.3107.4 Windows 10 x64 Edition Windows 10 x64 Edition

              https://cn.bing.com/search?q=No%20working%20C%20compiler%20found.
              搜技术相关的东西,请用必应。

            • 吉祥gg
              Clarke
              8 年前
              2017-6-11 21:01:57
              Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Windows 10 x64 Edition Windows 10 x64 Edition

              yum 安装下GCC就好了 因为系统没有gcc 无法编译

              • 哈哈
                吉祥gg
                8 年前
                2017-7-05 21:39:13
                Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Windows 10 x64 Edition Windows 10 x64 Edition

                我用的centos 安装上了ffmpeg 可以的 但在配置nginx的时候一直出各种各样的问题

  2. 8 年前
    2017-6-11 21:17:55
    Google Chrome 48.0.2564.97 Google Chrome 48.0.2564.97 Mac OS X  10.12.3 Mac OS X 10.12.3

    树莓派实验室转载了,特来感谢一下,多谢分享。
    http://shumeipai.nxez.com/2017/06/11/use-raspberry-pi-to-build-bilibili-vod.html

    • 博主
      树莓派实验室
      8 年前
      2017-6-11 21:20:23
      Google Chrome 60.0.3112.7 Google Chrome 60.0.3112.7 Windows 10 x64 Edition Windows 10 x64 Edition

      哇,第一次看见符合cc协议的转载?

  3. 8 年前
    2017-6-12 1:34:15
    Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Mac OS X  10.12.0 Mac OS X 10.12.0

    大神,我的CPU消耗为什么一直要90%以上?FFmpeg还能再优化吗?

    • 博主
      iChenwin
      8 年前
      2017-6-12 11:35:35
      Google Chrome 60.0.3112.7 Google Chrome 60.0.3112.7 Windows 10 x64 Edition Windows 10 x64 Edition

      如果有条件。。。开超频吧。。。
      记得加上散热风扇和散热铜片

      • 晨旭
        8 年前
        2017-6-18 12:42:07
        Google Chrome 58.0.3029.110 Google Chrome 58.0.3029.110 Mac OS X  10.12.0 Mac OS X 10.12.0

        好像有个h264_omx硬解码,可当初编译FFmpeg时候没有开启。用重编FFmpeg心好累啊。
        h264_omx有帮助的吧。看到有人树莓派直播CPU占用只用了5%。

  4. 8 年前
    2017-6-19 14:11:27
    Google Chrome 59.0.3071.86 Google Chrome 59.0.3071.86 Windows 10 x64 Edition Windows 10 x64 Edition

    参考博主的搭建了一个能点播MV的:https://aoaoao.me/live/index.php 直播地址:http://live.bilibili.com/3368800

    • 博主
      Aaron
      7 年前
      2017-11-13 20:44:55
      Vivaldi 1.93.955.42 Vivaldi 1.93.955.42 Windows 10 x64 Edition Windows 10 x64 Edition

      要是能解决切换视频时卡死的问题就好了,这样就能随便怎么玩了?

  5. 122
    8 年前
    2017-7-16 17:49:02
    UC Browser 6.1.2716.5 UC Browser 6.1.2716.5 Windows 10 x64 Edition Windows 10 x64 Edition

    怎么始终是在排队渲染中就没换过状态呢!

    • 博主
      122
      8 年前
      2017-7-17 9:18:08
      Google Chrome 60.0.3112.7 Google Chrome 60.0.3112.7 Windows 10 x64 Edition Windows 10 x64 Edition

      ff.py那个渲染处理脚本定时运行了吗

  6. 7 年前
    2017-8-14 16:37:13
    Safari 10.1.2 Safari 10.1.2 Mac OS X  10.12.6 Mac OS X 10.12.6

    厉害了

  7. tetsai
    7 年前
    2017-8-19 21:13:23
    Google Chrome 56.0.2924.87 Google Chrome 56.0.2924.87 Windows 10 x64 Edition Windows 10 x64 Edition

    代码高亮体验极差,无法复制,只能复制单行,因为每行代码是个单独的标签,平板、电脑均为此状

    • 博主
      tetsai
      7 年前
      2017-8-19 21:14:55
      Google Chrome 61.0.3159.5 Google Chrome 61.0.3159.5 Windows 10 x64 Edition Windows 10 x64 Edition

      解决方案1:点一下到别的页面,再点回来
      解决方案2:没发现可以双击复制全部代码的吗

      • tetsai
        晨旭
        7 年前
        2017-8-20 9:59:20
        Google Chrome 56.0.2924.87 Google Chrome 56.0.2924.87 Windows 10 x64 Edition Windows 10 x64 Edition

        双击没提示,而且也很奇怪,不顺手,像其他网站右上角一键复制比较好。点到别的页面我无力吐槽。关了js我才复制的。真心不推荐一行一个标签

        • 博主
          tetsai
          7 年前
          2017-8-20 11:46:36
          Google Chrome 61.0.3159.5 Google Chrome 61.0.3159.5 Windows 10 x64 Edition Windows 10 x64 Edition

          反正双击过后会出现一个单独的文本框,默认全选
          代码高亮是编辑器自带的,我没装过代码高亮插件

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇