相关推荐recommended
Docker nginx容器代理播放m3u8视频文件(HLS)
作者:mmseoamin日期:2024-01-19

文章目录

  • Docker Nginx容器代理播放M3U8文件教程
    • 获取Nginx Docker镜像
    • 设置Nginx配置文件
    • 用 ffmpeg 将 MP4 文件转换成 m3u8 文件
    • 运行Docker容器
    • 测试M3U8流
    • 其他问题
      • 我用vlc都能播放http://192.168.121.50/forest4kTest.m3u8和http://192.168.121.50/forest4kTest.mp4,那还要m3u8做什么,直接播放视频文件不就行了吗?

        Docker Nginx容器代理播放M3U8文件教程

        本教程将介绍如何在Docker中使用Nginx作为反向代理,以播放M3U8文件。我们会通过步骤详细解释每个过程,并提供命令和代码示例。

        获取Nginx Docker镜像

        我们用dockerfile构建镜像:

        (Dockerfile)

        FROM nginx:1.18
        

        然后用脚本构建镜像:

        (build_docker_image.sh)

        #!/bin/bash
        # 打印所有,包括注释
        # set -v
        # 打印执行命令
        # set -x
        # 命令出错退出
        set -e
        # 使用未初始化变量退出
        set -u
        # 设置变量
        IMAGE_NAME="kyai_nginx_x86"
        IMAGE_TAG="v1.18_20230724"
        # 检查依赖
        if ! [ -x "$(command -v docker)" ]; then
          echo 'Error: Docker is not installed.' >&2
          exit 1
        fi
        # 构建 Docker 镜像
        docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" .
        # 查看 Docker 镜像
        docker images
        

        然后可以用脚本把镜像导出为离线包:

        (docker_tar.sh)

        #!/bin/bash
        # 打印所有,包括注释
        # set -v
        # 打印执行命令
        # set -x
        # 命令出错退出
        set -e
        # 使用未初始化变量退出
        set -u
        REPOSITORY="kyai_nginx_x86"
        REP_TAG="v1.18_20230724"
        DOCKER_TAR="${REPOSITORY}-${REP_TAG}.tar"
        USER=root
        ################################################################################
        WHO=$(whoami | grep "${USER}$")
        if [ -z ${WHO} ]; then
            echo
            echo "Please change to \"${USER}\" user mode first!"
            echo
            exit 1
        fi
        echo "REPOSITORY: ${REPOSITORY}"
        echo "REP_TAG: ${REP_TAG}"
        echo "docker save -o ${DOCKER_TAR}..."
        docker save -o ${DOCKER_TAR} ${REPOSITORY}:${REP_TAG}
        chmod 777 $DOCKER_TAR
        

        Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第1张

        设置Nginx配置文件

        在运行Nginx Docker容器之前,我们需要设置一个Nginx配置文件。此文件将定义如何处理传入的HTTP请求。

        创建一个新的文件nginx.conf并输入以下内容:

        worker_processes 1;
        events {
            worker_connections 1024;
        }
        http {
            sendfile on;
            server {
                listen 80;
                location / {
                    root /usr/share/nginx/html;
                    types {
                        application/vnd.apple.mpegurl m3u8;
                        video/mp2t ts;
                    }
                    add_header Cache-Control no-cache;
                    add_header Access-Control-Allow-Origin *;
                }
            }
        }
        

        这个文件是一个Nginx服务器的配置文件,以下是对它的逐行解释:

        • worker_processes 1;:设置Nginx应使用的工作进程数。在大多数情况下,建议将此值设置为可用的CPU核心数。

        • events { worker_connections 1024; }:在events块中定义了每个工作进程允许的最大连接数。在这个例子中,每个工作进程允许最多1024个并发连接。

        • http { ... }:http块包含了所有的HTTP相关的配置。

          • sendfile on;:启用高效的文件传输模式。当启用时,Nginx可以直接从磁盘到TCP套接字进行数据传输,而无需在用户空间复制数据。

          • server { ... }:定义了一个服务器(或虚拟主机)的配置。

            • listen 80;:该服务器监听80端口,这通常是HTTP的默认端口。

            • location / { ... }:定义了对根路径(/)的请求的处理方式。所有URL路径都匹配此位置。

              • root /usr/share/nginx/html;:定义了服务器的根目录,即所有相对URL路径的基础路径。

              • types { ... }:定义了不同文件扩展名的MIME类型。在这个例子中,.m3u8文件被标记为application/vnd.apple.mpegurl,.ts文件被标记为video/mp2t。

              • add_header Cache-Control no-cache;:添加一个HTTP响应头,指示客户端不要缓存响应。

              • add_header Access-Control-Allow-Origin *;:添加一个HTTP响应头,允许任何来源的跨域请求(CORS)。

                这个配置文件将Nginx配置为一个简单的HTTP服务器,它可以为.m3u8和.ts文件提供服务,并禁用了响应缓存。

                用 ffmpeg 将 MP4 文件转换成 m3u8 文件

                假设我们有一个forest4kTest.mp4文件:

                Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第2张

                我们用下面命令将其转换为 m3u8 文件(我的ffmpeg版本是4.2.7-0ubuntu0.1):

                ffmpeg -i forest4kTest.mp4 -codec: copy -bsf:v h264_mp4toannexb -map 0 -f segment -segment_list forest4kTest.m3u8 -segment_time 10 forest4kTest%03d.ts
                

                在这个命令中:

                • -i forest4kTest.mp4指定输入文件。
                • -codec: copy表示不对视频进行重新编码,只是复制原始数据。
                • -bsf:v h264_mp4toannexb是一个比特流过滤器,用于将H264视频从MP4格式转换为MPEG2 TS格式,这是必需的,因为M3U8是基于TS的。
                • -map 0表示选择所有的流(例如,如果你的视频有音频和字幕)。
                • -f segment表示输出应该被分割成多个文件。
                • -segment_list output.m3u8指定输出的播放列表文件。
                • -segment_time 10表示每个TS段的最大长度(以秒为单位)。
                • forest4kTest%03d.ts是输出TS文件的名称模式。%03d将被替换为三位数的序号。

                  运行这个命令后,我们会得到一个名为forest4kTest.m3u8的播放列表文件,以及一系列的.ts文件。

                  Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第3张

                  我们可以用文本编辑器打开forest4kTest.m3u8看一下它里面内容:

                  #EXTM3U
                  #EXT-X-VERSION:3
                  #EXT-X-MEDIA-SEQUENCE:0
                  #EXT-X-ALLOW-CACHE:YES
                  #EXT-X-TARGETDURATION:11
                  #EXTINF:10.100311,
                  forest4kTest000.ts
                  #EXTINF:10.000311,
                  forest4kTest001.ts
                  #EXTINF:10.000311,
                  forest4kTest002.ts
                  #EXTINF:10.000311,
                  forest4kTest003.ts
                  #EXTINF:10.000311,
                  forest4kTest004.ts
                  #EXTINF:10.000311,
                  forest4kTest005.ts
                  #EXTINF:10.000311,
                  forest4kTest006.ts
                  #EXTINF:10.000311,
                  forest4kTest007.ts
                  #EXTINF:10.000311,
                  forest4kTest008.ts
                  #EXTINF:10.000311,
                  forest4kTest009.ts
                  #EXTINF:0.633311,
                  forest4kTest010.ts
                  #EXT-X-ENDLIST
                  

                  关于里面内容的解释,可以参考我另外一篇文章:M3u8播放列表文件(索引格式文件)、HLS(HTTP Live Streaming)协议介绍

                  运行Docker容器

                  我们需要写一个 run 容器的脚本,首先看看我的文件结构:

                  Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第4张

                  再看看我的run容器脚本:

                  (install.sh)

                  #!/bin/bash
                  # 打印所有,包括注释
                  # set -v
                  # 打印执行命令
                  # set -x
                  # 命令出错退出
                  set -e
                  # 使用未初始化变量退出
                  set -u
                  echo -e "\033[1;33m"
                  echo " _           _        _ _               _            "
                  echo "(_)_ __  ___| |_ __ _| | |  _ __   __ _(_)_ __ __  __"
                  echo "| | '_ \/ __| __/ _' | | | | '_ \ / _' | | '_ \\\\ \/ /"
                  echo "| | | | \__ \ || (_| | | | | | | | (_| | | | | |>  < "
                  echo "|_|_| |_|___/\__\__,_|_|_| |_| |_|\__, |_|_| |_/_/\_\"
                  echo "                                  |___/              "
                  echo -e "3[0m"
                  USER=root
                  # USER_HOME=/root
                  # --------------------------------------------------------------------------
                  CONTAINER_NAME_NGINX="kyai_nginx"
                  TAR_NGINX="kyai_nginx_x86-v1.18_20230724.tar"
                  IMAGE_NAME_NGINX="kyai_nginx_x86"
                  TAG_NGINX="v1.18_20230724"
                  R_DEPLOY_PATH_NGINX="."
                  # 检查是否是root
                  WHO=$(whoami | grep "${USER}$")
                  if [ -z "${WHO}" ]; then
                      echo
                      echo "Please change to \"${USER}\" user mode first!"
                      echo
                      exit 1
                  fi
                  # --------------------------------------------------------------------------
                  # 获取脚本所在路径
                  SCRIPT_LOCATION=$(
                      cd "$(dirname "")" || {
                          echo "cd Failure"
                          exit 1
                      }
                      pwd
                  )
                  # echo "SCRIPT_LOCATION = $SCRIPT_LOCATION"
                  chmod 777 ${SCRIPT_LOCATION} -R
                  # --------------------------------------------------------------------------
                  # Function to create container
                  # Arguments: $1 - Container name
                  #            $2 - Docker TAR filename
                  #            $3 - Image name
                  #            $4 - Image tag
                  #            $5 - Deploy path
                  #            $6 - The function to run container
                  function create_container {
                      local CONTAINER_NAME="$1"
                      local DOCKER_TAR="$2"
                      local IMAGE_NAME="$3"
                      local IMAGE_TAG="$4"
                      local DEPLOY_PATH="$5"
                      local docker_run="$6"
                      # Check if container already exists
                      if [[ "$(docker ps -aqf "name=^$CONTAINER_NAME$")" ]]; then
                          echo "Container $CONTAINER_NAME already exists."
                          read -p "Do you want to delete it? (y/n)" answer
                          case ${answer:0:1} in
                          y | Y)
                              # Stop and remove container
                              docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME
                              # Check command result
                              if [ $? -ne 0 ]; then
                                  echo "Failed to stop or remove container $CONTAINER_NAME."
                                  exit 1
                              fi
                              echo "Container $CONTAINER_NAME stopped and removed successfully."
                              ;;
                          *)
                              return 0
                              ;;
                          esac
                      fi
                      # Check if image already exists
                      if ! docker images | awk '{print $1":"$2}' | grep -q "^${IMAGE_NAME}:${IMAGE_TAG}$"; then
                          # Check if Docker TAR file exists
                          if [ ! -e "${DEPLOY_PATH}/${DOCKER_TAR}" ]; then
                              echo "${DEPLOY_PATH}/${DOCKER_TAR} does not exist!"
                              exit 1
                          fi
                          echo "Loading Docker image from ${DOCKER_TAR}..."
                          docker load -i "${DEPLOY_PATH}/${DOCKER_TAR}"
                          if [ $? -ne 0 ]; then
                              echo "Failed to load Docker image from ${DOCKER_TAR}!"
                              exit 1
                          fi
                      fi
                      echo "Docker image ${IMAGE_NAME}:${IMAGE_TAG} already exists."
                      # run container
                      $docker_run "$CONTAINER_NAME" "$DOCKER_TAR" "$IMAGE_NAME" "$IMAGE_TAG" "$DEPLOY_PATH"
                      if [ $? -ne 0 ]; then
                          echo "$docker_run error!"
                          exit 1
                      fi
                  }
                  # --------------------------------------------------------------------------
                  # 部署 nginx 服务
                  # The function to run container of nginx
                  # Arguments: $1 - Container name
                  #            $2 - Docker TAR filename
                  #            $3 - Image name
                  #            $4 - Image tag
                  #            $5 - Deploy path
                  function docker_run_nginx {
                  local CONTAINER_NAME="$1" local DOCKER_TAR="$2" local IMAGE_NAME="$3" local IMAGE_TAG="$4" local DEPLOY_PATH="$5" docker run -d \ --restart=always \ -p 80:80 \ -v $SCRIPT_LOCATION/$R_DEPLOY_PATH_NGINX/mount/m3u8/files:/usr/share/nginx/html \ -v $SCRIPT_LOCATION/$R_DEPLOY_PATH_NGINX/mount/conf/nginx.conf:/etc/nginx/nginx.conf \ --name $CONTAINER_NAME \ $IMAGE_NAME:$IMAGE_TAG # -v $SCRIPT_LOCATION/$R_DEPLOY_PATH_NGINX/../web/html/web:/ky/java/nginx/html/web \ if [ $? -ne 0 ]; then echo "docker run $CONTAINER_NAME error!" exit 1 fi echo "docker run $CONTAINER_NAME [$IMAGE_NAME:$IMAGE_TAG] successfully." } create_container "$CONTAINER_NAME_NGINX" "$TAR_NGINX" "$IMAGE_NAME_NGINX" "$TAG_NGINX" "$SCRIPT_LOCATION/$R_DEPLOY_PATH_NGINX" docker_run_nginx if [ $? -ne 0 ]; then echo "Container $CONTAINER_NAME_NGINX create failed." exit 1 fi echo echo "$CONTAINER_NAME_NGINX deploy successfully" echo

                  这个脚本将启动一个新的Docker容器,并映射主机的80端口到容器的80端口。

                  运行脚本后,我们可以看到如下结果:

                  Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第5张

                  测试M3U8流

                  可以通过访问http://localhost:80/yourfile.m3u8或http://ipaddress:80/yourfile.m3u8来播放m3u8文件(80端口也可以省略掉)。

                  比如,我在windows上用VLC打开http://192.168.121.50/forest4kTest.m3u8(其中192.168.121.50是我Net模式虚拟机的ip地址):

                  Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第6张

                  Docker nginx容器代理播放m3u8视频文件(HLS),在这里插入图片描述,第7张

                  m3u8视频流能被播放出来。

                  其他问题

                  我用vlc都能播放http://192.168.121.50/forest4kTest.m3u8和http://192.168.121.50/forest4kTest.mp4,那还要m3u8做什么,直接播放视频文件不就行了吗?

                  确实,使用直接的视频链接(如.mp4文件)可以在许多情况下播放视频。然而,M3U8作为HTTP Live Streaming(HLS)协议的一部分,提供了许多其他优势和高级功能,包括:
                  1. 自适应流媒体:M3U8允许提供不同质量和分辨率的视频流,以适应各种网络条件和设备能力。客户端可以在播放过程中无缝切换不同质量的流,以优化用户体验。
                  2. 实时或点播流:M3U8可以用于实时的流媒体广播,也可以用于点播内容。
                  3. 容错性:由于M3U8将媒体内容分割成多个小段,所以即使在下载过程中出现问题,也只会影响到当前的段,而不是整个视频。
                  4. 加密:M3U8支持对媒体段进行AES-128或SAMPLE-AES加密,以保护内容安全。
                  5. 跨平台和广泛支持:M3U8和HLS协议被广泛地支持,在各种设备和平台上都可以播放,包括iOS、Android、Windows、macOS等。

                  因此,虽然在某些情况下,直接链接到视频文件可能更简单,但使用M3U8和HLS协议可以提供更强大和灵活的流媒体解决方案。
                   
                   公司建站价格  怎么注册公司营业执照  福田做网站的公司  宝鸡网站建设  一键建站免费  网站开发流程