media-utils.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * 媒体工具类 - 处理视频流地址转换
  3. */
  4. // 流协议类型
  5. export const STREAM_PROTOCOLS = {
  6. RTMP: 'rtmp://',
  7. HTTP_FLV: ['http://', 'https://'],
  8. HLS: ['http://', 'https://'],
  9. WS_FLV: ['ws://', 'wss://']
  10. }
  11. /**
  12. * 判断视频流类型
  13. * @param {String} url 视频流地址
  14. * @returns {String} 流类型,如 'rtmp', 'http-flv', 'hls', 'ws-flv'
  15. */
  16. export const getStreamType = (url) => {
  17. if (!url) return null
  18. const lowerUrl = url.toLowerCase()
  19. if (lowerUrl.startsWith(STREAM_PROTOCOLS.RTMP)) {
  20. return 'rtmp'
  21. }
  22. if (STREAM_PROTOCOLS.HTTP_FLV.some(protocol => lowerUrl.startsWith(protocol)) && lowerUrl.endsWith('.flv')) {
  23. return 'http-flv'
  24. }
  25. if (STREAM_PROTOCOLS.HLS.some(protocol => lowerUrl.startsWith(protocol)) &&
  26. (lowerUrl.endsWith('.m3u8') || lowerUrl.includes('.m3u8?'))) {
  27. return 'hls'
  28. }
  29. if (STREAM_PROTOCOLS.WS_FLV.some(protocol => lowerUrl.startsWith(protocol)) &&
  30. (lowerUrl.endsWith('.flv') || lowerUrl.includes('.flv?') || lowerUrl.includes('live.flv'))) {
  31. return 'ws-flv'
  32. }
  33. return 'unknown'
  34. }
  35. /**
  36. * 检查流是否在小程序中可播放
  37. * @param {String} url 视频流地址
  38. * @returns {Boolean} 是否可在小程序中播放
  39. */
  40. export const isPlayableInMiniProgram = (url) => {
  41. const streamType = getStreamType(url)
  42. // 小程序只支持RTMP和HLS(m3u8)
  43. return streamType === 'rtmp' || streamType === 'hls'
  44. }
  45. /**
  46. * 构建适用于不同平台的流地址
  47. * @param {String} originalUrl 原始流地址
  48. * @param {Object} options 配置选项
  49. * @returns {Object} 不同平台适用的流地址
  50. */
  51. export const buildPlatformStreamUrls = (originalUrl, options = {}) => {
  52. // 提取流的关键信息 (比如设备ID)
  53. const streamType = getStreamType(originalUrl)
  54. const { streamServer = {}, fallbackToHls = true } = options
  55. // 获取流服务器地址
  56. const { rtmpServer, hlsServer, wsFlvServer } = streamServer
  57. // 提取设备ID或流标识 (示例: 使用正则表达式提取)
  58. const streamIdMatch = originalUrl.match(/(\d+_\d+\.live\.flv)/) ||
  59. originalUrl.match(/([^/]+)\.m3u8/) ||
  60. originalUrl.match(/stream=([^&]+)/)
  61. const streamId = streamIdMatch ? streamIdMatch[1] : null
  62. if (!streamId) {
  63. // 如果无法提取流ID,则返回原始URL
  64. return {
  65. h5Url: originalUrl,
  66. miniProgramUrl: isPlayableInMiniProgram(originalUrl) ? originalUrl : null
  67. }
  68. }
  69. // 构建不同平台的URL
  70. const urls = {
  71. h5Url: originalUrl, // 默认H5使用原始URL
  72. miniProgramUrl: null
  73. }
  74. // 微信小程序优先使用RTMP和HLS
  75. if (rtmpServer && streamType !== 'rtmp') {
  76. // 构建RTMP URL (小程序支持)
  77. urls.miniProgramUrl = `${rtmpServer}/${streamId.replace('.live.flv', '')}`
  78. } else if (hlsServer && streamType !== 'hls') {
  79. // 构建HLS URL (小程序支持)
  80. urls.miniProgramUrl = `${hlsServer}/${streamId.replace('.live.flv', '.m3u8')}`
  81. } else if (isPlayableInMiniProgram(originalUrl)) {
  82. // 原URL已经是小程序可播放格式
  83. urls.miniProgramUrl = originalUrl
  84. } else if (fallbackToHls) {
  85. // 假设存在通用HLS地址可以使用
  86. const deviceId = streamId.split('_')[0] || streamId
  87. urls.miniProgramUrl = `${hlsServer || 'https://stream.example.com/hls'}/${deviceId}.m3u8`
  88. }
  89. return urls
  90. }
  91. export default {
  92. getStreamType,
  93. isPlayableInMiniProgram,
  94. buildPlatformStreamUrls
  95. }