Parcourir la source

feat(ffmpeg): add WHIP support compilation script and enhance live stream functionality

- Introduced a new script for compiling FFmpeg with WHIP support, including intelligent dependency checks and installation steps for various operating systems.
- Updated LiveStreamDTO to include optional fields for taskStreamSn and playbackUrl.
- Enhanced the live stream view to parse playbackUrl for videoId and customerDomain, improving stream management and playback information retrieval.
yb il y a 1 semaine
Parent
commit
0c23d9856a
3 fichiers modifiés avec 384 ajouts et 6 suppressions
  1. 337 0
      scripts/checkWhip.sh
  2. 2 0
      src/types/index.ts
  3. 45 6
      src/views/live-stream/index.vue

+ 337 - 0
scripts/checkWhip.sh

@@ -0,0 +1,337 @@
+#!/bin/bash
+# ============================================
+# FFmpeg WHIP 支持编译脚本
+# 智能检测:已安装则跳过,未安装则编译
+# ============================================
+
+set -e
+
+# 配置
+BUILD_DIR="$HOME/ffmpeg-whip-build"
+INSTALL_PREFIX="/usr/local/ffmpeg-whip"
+NPROC=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
+
+echo ""
+echo "╔══════════════════════════════════════════════════════════════╗"
+echo "║         FFmpeg WHIP 支持编译脚本 (智能检测版)                  ║"
+echo "║         编译目录: $BUILD_DIR"
+echo "║         安装目录: $INSTALL_PREFIX"
+echo "║         CPU 核心: $NPROC"
+echo "╚══════════════════════════════════════════════════════════════╝"
+echo ""
+
+# ==================== 检查是否已安装 ====================
+echo "┌──────────────────────────────────────────────────────────────┐"
+echo "│ 预检查: FFmpeg WHIP 支持                                      │"
+echo "└──────────────────────────────────────────────────────────────┘"
+
+if [ -x "$INSTALL_PREFIX/bin/ffmpeg" ]; then
+    WHIP_CHECK=$("$INSTALL_PREFIX/bin/ffmpeg" -formats 2>/dev/null | grep -c "whip" || echo 0)
+    if [ "$WHIP_CHECK" -gt 0 ]; then
+        echo "✅ FFmpeg WHIP 已安装,无需重新编译"
+        "$INSTALL_PREFIX/bin/ffmpeg" -version | head -1
+        echo ""
+        echo "如需强制重新编译,请删除后再运行:"
+        echo "  sudo rm -rf $INSTALL_PREFIX"
+        echo "  ./scripts/build-ffmpeg-whip.sh"
+        exit 0
+    fi
+fi
+
+echo "未检测到支持 WHIP 的 FFmpeg,开始编译..."
+echo ""
+
+# 创建目录
+mkdir -p "$BUILD_DIR"
+cd "$BUILD_DIR"
+
+# ==================== 步骤 1: 安装依赖 ====================
+echo "┌──────────────────────────────────────────────────────────────┐"
+echo "│ 步骤 1/3: 检查并安装依赖                                      │"
+echo "└──────────────────────────────────────────────────────────────┘"
+
+install_deps_centos() {
+    echo "检测到 CentOS/RHEL,检查依赖..."
+
+    # 检查 Development Tools
+    if ! rpm -q gcc &>/dev/null; then
+        echo "安装 Development Tools..."
+        sudo yum groupinstall -y "Development Tools"
+    else
+        echo "✓ Development Tools 已安装"
+    fi
+
+    # 尝试安装 EPEL (需要先安装,因为 x264 在 EPEL 里)
+    if ! rpm -q epel-release &>/dev/null; then
+        echo "安装 EPEL..."
+        sudo yum install -y epel-release || true
+    fi
+
+    # 检查其他依赖
+    DEPS="cmake git openssl-devel nasm x264-devel opus-devel"
+    for dep in $DEPS; do
+        if ! rpm -q $dep &>/dev/null; then
+            echo "安装 $dep..."
+            sudo yum install -y $dep || true
+        else
+            echo "✓ $dep 已安装"
+        fi
+    done
+}
+
+install_deps_ubuntu() {
+    echo "检测到 Debian/Ubuntu,检查依赖..."
+
+    DEPS="build-essential cmake git pkg-config libssl-dev nasm libx264-dev libopus-dev"
+    MISSING=""
+
+    for dep in $DEPS; do
+        if ! dpkg -s $dep &>/dev/null; then
+            MISSING="$MISSING $dep"
+        else
+            echo "✓ $dep 已安装"
+        fi
+    done
+
+    if [ -n "$MISSING" ]; then
+        echo "安装缺失依赖:$MISSING"
+        sudo apt-get update
+        sudo apt-get install -y $MISSING
+    fi
+}
+
+install_deps_macos() {
+    echo "检测到 macOS,检查依赖..."
+
+    DEPS="cmake openssl nasm pkg-config x264 opus"
+    for dep in $DEPS; do
+        if ! brew list $dep &>/dev/null; then
+            echo "安装 $dep..."
+            brew install $dep || true
+        else
+            echo "✓ $dep 已安装"
+        fi
+    done
+}
+
+# 根据系统选择安装方式
+if [[ "$OSTYPE" == "darwin"* ]]; then
+    install_deps_macos
+elif command -v yum &>/dev/null; then
+    install_deps_centos
+elif command -v apt-get &>/dev/null; then
+    install_deps_ubuntu
+elif command -v dnf &>/dev/null; then
+    echo "检测到 Fedora/RHEL 8+,使用 dnf..."
+    sudo dnf groupinstall -y "Development Tools"
+    sudo dnf install -y epel-release || true
+    sudo dnf install -y cmake git openssl-devel nasm x264-devel opus-devel
+else
+    echo "⚠️ 未知系统,请手动安装: cmake git openssl-devel nasm"
+fi
+
+echo "✅ 依赖检查完成"
+echo ""
+
+# ==================== 步骤 2: 编译 FFmpeg ====================
+echo "┌──────────────────────────────────────────────────────────────┐"
+echo "│ 步骤 2/3: 编译 FFmpeg (支持 WHIP)                             │"
+echo "└──────────────────────────────────────────────────────────────┘"
+
+cd "$BUILD_DIR"
+
+if [ ! -d "ffmpeg-git" ]; then
+    echo "下载 FFmpeg 源码..."
+    git clone --depth 1 https://git.ffmpeg.org/ffmpeg.git ffmpeg-git
+else
+    echo "FFmpeg 源码已存在,重置到最新版本..."
+    cd ffmpeg-git
+    git fetch origin
+    git reset --hard origin/master
+    cd ..
+fi
+
+cd ffmpeg-git
+
+# ==================== 应用 WHIP Bug 修复 ====================
+echo ""
+echo "应用 WHIP muxer 补丁..."
+
+WHIP_FILE="libavformat/whip.c"
+if [ -f "$WHIP_FILE" ]; then
+    # 跨平台 sed 函数 (兼容 macOS 和 Linux)
+    sed_inplace() {
+        if [[ "$OSTYPE" == "darwin"* ]]; then
+            sed -i '' "$@"
+        else
+            sed -i "$@"
+        fi
+    }
+
+    # Bug Fix #1: rtcp-fb 缺少冒号
+    if grep -q '"a=rtcp-fb%u' "$WHIP_FILE"; then
+        echo "  修复 Bug #1: rtcp-fb 缺少冒号..."
+        sed_inplace 's/"a=rtcp-fb%u/"a=rtcp-fb:%u/g' "$WHIP_FILE"
+        echo "  ✓ Bug #1 已修复"
+    else
+        echo "  ✓ Bug #1 已经修复或不存在"
+    fi
+
+    # Bug Fix #2: BUNDLE 和 mid 硬编码问题 (针对 video-only 模式)
+    if grep -q 'BUNDLE 0 1' "$WHIP_FILE"; then
+        echo "  修复 Bug #2: BUNDLE/mid 硬编码问题..."
+        cp "$WHIP_FILE" "${WHIP_FILE}.orig"
+        sed_inplace 's/BUNDLE 0 1/BUNDLE 0/g' "$WHIP_FILE"
+        sed_inplace 's/"a=mid:1\\r\\n"/"a=mid:0\\r\\n"/g' "$WHIP_FILE"
+        if ! grep -q 'BUNDLE 0 1' "$WHIP_FILE"; then
+            echo "  ✓ Bug #2 已修复 (BUNDLE 改为 0, 支持 video-only 模式)"
+        else
+            echo "  ⚠ BUNDLE 修复可能未完全生效"
+        fi
+    else
+        echo "  ✓ Bug #2 已经修复或不存在"
+    fi
+    echo "✅ WHIP 补丁应用完成"
+else
+    echo "⚠️ 未找到 WHIP 源文件,跳过补丁"
+fi
+echo ""
+
+echo "配置 FFmpeg..."
+
+# 清理之前的编译
+make distclean 2>/dev/null || true
+
+# 设置编译参数
+EXTRA_CFLAGS=""
+EXTRA_LDFLAGS=""
+
+# macOS 特殊处理: OpenSSL, x264, opus 路径
+if [[ "$OSTYPE" == "darwin"* ]]; then
+    OPENSSL_PREFIX=$(brew --prefix openssl)
+    X264_PREFIX=$(brew --prefix x264)
+    OPUS_PREFIX=$(brew --prefix opus)
+    export PKG_CONFIG_PATH="$OPENSSL_PREFIX/lib/pkgconfig:$X264_PREFIX/lib/pkgconfig:$OPUS_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
+    EXTRA_CFLAGS="-I$OPENSSL_PREFIX/include -I$X264_PREFIX/include -I$OPUS_PREFIX/include"
+    EXTRA_LDFLAGS="-L$OPENSSL_PREFIX/lib -L$X264_PREFIX/lib -L$OPUS_PREFIX/lib"
+    echo "macOS 库路径:"
+    echo "  OpenSSL: $OPENSSL_PREFIX"
+    echo "  x264: $X264_PREFIX"
+    echo "  opus: $OPUS_PREFIX"
+fi
+
+echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
+echo ""
+
+# 配置 FFmpeg
+# WHIP muxer 依赖: dtls_protocol -> openssl
+# 视频编码: libx264 (支持 -preset)
+# 音频编码: libopus
+./configure \
+    --prefix="$INSTALL_PREFIX" \
+    --enable-gpl \
+    --enable-nonfree \
+    --enable-openssl \
+    --enable-libx264 \
+    --enable-libopus \
+    --extra-cflags="$EXTRA_CFLAGS" \
+    --extra-ldflags="$EXTRA_LDFLAGS"
+
+# 检查关键功能是否被启用
+echo ""
+echo "检查编译配置..."
+
+CONFIG_OK=true
+
+# 检查 WHIP
+if grep -q "CONFIG_WHIP_MUXER=yes" ffbuild/config.mak 2>/dev/null; then
+    echo "✅ WHIP muxer 已启用"
+else
+    echo "❌ WHIP muxer 未启用"
+    CONFIG_OK=false
+fi
+
+# 检查 libx264
+if grep -q "CONFIG_LIBX264_ENCODER=yes" ffbuild/config.mak 2>/dev/null; then
+    echo "✅ libx264 编码器已启用"
+else
+    echo "❌ libx264 编码器未启用"
+    CONFIG_OK=false
+fi
+
+# 检查 libopus
+if grep -q "CONFIG_LIBOPUS_ENCODER=yes" ffbuild/config.mak 2>/dev/null; then
+    echo "✅ libopus 编码器已启用"
+else
+    echo "❌ libopus 编码器未启用"
+    CONFIG_OK=false
+fi
+
+if [ "$CONFIG_OK" = false ]; then
+    echo ""
+    echo "调试信息:"
+    grep -E "(openssl|dtls|whip|x264|opus)" ffbuild/config.mak 2>/dev/null | head -20 || true
+    echo ""
+    echo "可能原因:"
+    echo "  1. 依赖库未正确安装"
+    echo "  2. 库路径未正确配置"
+    echo ""
+    exit 1
+fi
+
+echo ""
+echo "编译 FFmpeg (这可能需要 10-20 分钟)..."
+make -j$NPROC
+
+echo "安装 FFmpeg..."
+sudo make install
+
+echo "✅ FFmpeg 编译完成"
+echo ""
+
+# ==================== 步骤 3: 验证 ====================
+echo "┌──────────────────────────────────────────────────────────────┐"
+echo "│ 步骤 3/3: 验证安装                                            │"
+echo "└──────────────────────────────────────────────────────────────┘"
+
+echo "FFmpeg 版本:"
+"$INSTALL_PREFIX/bin/ffmpeg" -version | head -3
+
+echo ""
+echo "功能检查:"
+
+# WHIP 支持
+if "$INSTALL_PREFIX/bin/ffmpeg" -formats 2>/dev/null | grep -q whip; then
+    echo "✅ WHIP 格式支持已启用"
+    "$INSTALL_PREFIX/bin/ffmpeg" -formats 2>/dev/null | grep whip
+else
+    echo "❌ WHIP 格式支持未找到"
+    exit 1
+fi
+
+# libx264 编码器
+if "$INSTALL_PREFIX/bin/ffmpeg" -encoders 2>/dev/null | grep -q libx264; then
+    echo "✅ libx264 编码器已启用"
+else
+    echo "❌ libx264 编码器未找到"
+    exit 1
+fi
+
+# libopus 编码器
+if "$INSTALL_PREFIX/bin/ffmpeg" -encoders 2>/dev/null | grep -q libopus; then
+    echo "✅ libopus 编码器已启用"
+else
+    echo "❌ libopus 编码器未找到"
+    exit 1
+fi
+
+echo ""
+echo "╔══════════════════════════════════════════════════════════════╗"
+echo "║                    ✅ 编译完成!                               ║"
+echo "╠══════════════════════════════════════════════════════════════╣"
+echo "║  FFmpeg 路径: $INSTALL_PREFIX/bin/ffmpeg"
+echo "║                                                              ║"
+echo "║  部署应用:                                                    ║"
+echo "║    cd /home/fyd/tp/tg-live-game-service                      ║"
+echo "║    ./scripts/deploy.sh                                       ║"
+echo "╚══════════════════════════════════════════════════════════════╝"

+ 2 - 0
src/types/index.ts

@@ -486,6 +486,8 @@ export interface LiveStreamDTO {
   remark?: string
   remark?: string
   createdAt: string
   createdAt: string
   updatedAt: string
   updatedAt: string
+  taskStreamSn?: string
+  playbackUrl?: string
 }
 }
 
 
 // LiveStream 列表请求参数
 // LiveStream 列表请求参数

+ 45 - 6
src/views/live-stream/index.vue

@@ -837,33 +837,72 @@ async function handleStopStream(row: LiveStreamDTO) {
   }
   }
 }
 }
 
 
+// 从 playbackUrl 解析 videoId 和 customerDomain
+function parsePlaybackUrl(playbackUrl: string): { videoId: string; customerDomain: string } | null {
+  try {
+    const url = new URL(playbackUrl)
+    const customerDomain = url.hostname
+    // URL 格式: https://domain/{videoId}/webRTC/play 或 https://domain/{videoId}/iframe
+    const pathParts = url.pathname.split('/').filter(Boolean)
+    if (pathParts.length > 0) {
+      return { videoId: pathParts[0], customerDomain }
+    }
+  } catch (e) {
+    console.error('解析 playbackUrl 失败', e)
+  }
+  return null
+}
+
 // 查看流媒体
 // 查看流媒体
 async function handleViewCloudflare(row: LiveStreamDTO) {
 async function handleViewCloudflare(row: LiveStreamDTO) {
   currentMediaStream.value = row
   currentMediaStream.value = row
 
 
+  // 默认值
+  let videoId = ''
+  let customerDomain = 'customer-pj89kn2ke2tcuh19.cloudflarestream.com'
+
+  // 优先从 playbackUrl 解析
+  if (row.playbackUrl) {
+    const parsed = parsePlaybackUrl(row.playbackUrl)
+    if (parsed) {
+      videoId = parsed.videoId
+      customerDomain = parsed.customerDomain
+    }
+  }
+
   // 尝试获取播放信息
   // 尝试获取播放信息
   if (row.streamSn) {
   if (row.streamSn) {
     try {
     try {
       const res = await getStreamPlayback(row.streamSn)
       const res = await getStreamPlayback(row.streamSn)
       if (res.success && res.data) {
       if (res.success && res.data) {
-        // 从播放信息中提取 Cloudflare 配置
         playbackInfo.value = {
         playbackInfo.value = {
-          videoId: row.streamSn,
-          customerDomain: 'customer-pj89kn2ke2tcuh19.cloudflarestream.com',
+          videoId: videoId || row.streamSn,
+          customerDomain,
           hlsUrl: res.data.hlsUrl,
           hlsUrl: res.data.hlsUrl,
           whepUrl: res.data.whepUrl,
           whepUrl: res.data.whepUrl,
           isLive: res.data.isLive
           isLive: res.data.isLive
         }
         }
+      } else {
+        playbackInfo.value = {
+          videoId: videoId || row.streamSn,
+          customerDomain,
+          isLive: false
+        }
       }
       }
     } catch (error) {
     } catch (error) {
       console.error('获取播放信息失败', error)
       console.error('获取播放信息失败', error)
-      // 使用默认配置
       playbackInfo.value = {
       playbackInfo.value = {
-        videoId: row.streamSn,
-        customerDomain: 'customer-pj89kn2ke2tcuh19.cloudflarestream.com',
+        videoId: videoId || row.streamSn,
+        customerDomain,
         isLive: false
         isLive: false
       }
       }
     }
     }
+  } else if (videoId) {
+    playbackInfo.value = {
+      videoId,
+      customerDomain,
+      isLive: false
+    }
   }
   }
 
 
   mediaDrawerVisible.value = true
   mediaDrawerVisible.value = true