Enhance video streaming capabilities and UI integration
- Added support for streaming video files with proper MIME type handling in the media API. - Implemented transcoding functionality for H.264 compatibility on-the-fly using FFmpeg. - Updated VideoModal component to utilize Video.js for improved video playback experience. - Enhanced user interface with download options and better error handling for video playback. - Updated package.json and package-lock.json to include new dependencies for video.js and related types.
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import React from 'react'
|
||||
import React, { useRef, useEffect } from 'react'
|
||||
import videojs from 'video.js'
|
||||
import 'video.js/dist/video-js.css'
|
||||
|
||||
const BASE = (import.meta as any).env?.VITE_MEDIA_API_URL || (import.meta as any).env?.VITE_VISION_API_URL || '/api'
|
||||
|
||||
type Props = {
|
||||
@@ -7,8 +10,59 @@ type Props = {
|
||||
}
|
||||
|
||||
export const VideoModal: React.FC<Props> = ({ fileId, onClose }) => {
|
||||
if (!fileId) return null
|
||||
const src = `${BASE}/videos/stream?file_id=${encodeURIComponent(fileId)}`
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const playerRef = useRef<any>(null)
|
||||
// Use transcoded endpoint for browser compatibility (H.264)
|
||||
const src = fileId ? `${BASE}/videos/stream-transcoded?file_id=${encodeURIComponent(fileId)}` : null
|
||||
|
||||
useEffect(() => {
|
||||
if (!fileId || !src || !videoRef.current) return
|
||||
|
||||
// Initialize Video.js player
|
||||
const player = videojs(videoRef.current, {
|
||||
controls: true,
|
||||
autoplay: true,
|
||||
preload: 'auto',
|
||||
fluid: true,
|
||||
responsive: true,
|
||||
playbackRates: [0.5, 1, 1.25, 1.5, 2],
|
||||
sources: [
|
||||
{
|
||||
src: src,
|
||||
type: 'video/mp4'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
playerRef.current = player
|
||||
|
||||
player.on('error', () => {
|
||||
const error = player.error()
|
||||
if (error) {
|
||||
console.error('Video.js error:', error)
|
||||
console.error('Error code:', error.code)
|
||||
console.error('Error message:', error.message)
|
||||
}
|
||||
})
|
||||
|
||||
player.on('loadedmetadata', () => {
|
||||
console.log('Video metadata loaded, duration:', player.duration())
|
||||
})
|
||||
|
||||
player.on('canplay', () => {
|
||||
console.log('Video can play')
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
if (playerRef.current) {
|
||||
playerRef.current.dispose()
|
||||
playerRef.current = null
|
||||
}
|
||||
}
|
||||
}, [fileId, src])
|
||||
|
||||
if (!fileId || !src) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -31,16 +85,28 @@ export const VideoModal: React.FC<Props> = ({ fileId, onClose }) => {
|
||||
</button>
|
||||
|
||||
<div className="p-4 bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Video Player</h3>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">Watch your recording</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Video Player</h3>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">Watch your recording</p>
|
||||
</div>
|
||||
<a
|
||||
href={src}
|
||||
download
|
||||
className="px-3 py-1.5 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
Download Video
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 bg-black">
|
||||
<div className="relative w-full" style={{ aspectRatio: '16/9', maxHeight: '70vh' }}>
|
||||
<video
|
||||
src={src}
|
||||
controls
|
||||
className="w-full h-full rounded-lg object-contain"
|
||||
autoPlay
|
||||
ref={videoRef}
|
||||
className="video-js vjs-default-skin w-full h-full"
|
||||
playsInline
|
||||
key={fileId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,5 +116,3 @@ export const VideoModal: React.FC<Props> = ({ fileId, onClose }) => {
|
||||
}
|
||||
|
||||
export default VideoModal
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user