Video Producer Skill
I help you build video players, handle video streaming, and create engaging video experiences.
What I Do
Video Playback:
Custom video players with controls Adaptive bitrate streaming (HLS, DASH) Picture-in-picture mode Fullscreen support
Video Features:
Subtitles and captions Quality selection Playback speed control Thumbnail previews
Streaming:
Live video streaming Video on demand (VOD) Progressive download Adaptive streaming Custom Video Player // components/VideoPlayer.tsx 'use client' import { useRef, useState, useEffect } from 'react'
interface VideoPlayerProps { src: string poster?: string title?: string }
export function VideoPlayer({ src, poster, title }: VideoPlayerProps) {
const videoRef = useRef
useEffect(() => { const video = videoRef.current if (!video) return
const updateTime = () => setCurrentTime(video.currentTime)
const updateDuration = () => setDuration(video.duration)
const handleEnded = () => setPlaying(false)
video.addEventListener('timeupdate', updateTime)
video.addEventListener('loadedmetadata', updateDuration)
video.addEventListener('ended', handleEnded)
return () => {
video.removeEventListener('timeupdate', updateTime)
video.removeEventListener('loadedmetadata', updateDuration)
video.removeEventListener('ended', handleEnded)
}
}, [])
const togglePlay = () => { if (!videoRef.current) return
if (playing) {
videoRef.current.pause()
} else {
videoRef.current.play()
}
setPlaying(!playing)
}
const handleSeek = (e: React.ChangeEvent
const handleVolumeChange = (e: React.ChangeEvent
const toggleFullscreen = () => { if (!videoRef.current) return
if (!fullscreen) {
videoRef.current.requestFullscreen()
} else {
document.exitFullscreen()
}
setFullscreen(!fullscreen)
}
const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return ${mins}:${secs.toString().padStart(2, '0')}
}
return (
{title}
<video
ref={videoRef}
src={src}
poster={poster}
onClick={togglePlay}
className="w-full"
/>
{showControls && (
<div className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent">
{/* Progress Bar */}
<input
type="range"
min="0"
max={duration || 0}
value={currentTime}
onChange={handleSeek}
className="w-full mb-2"
/>
<div className="flex items-center gap-4">
{/* Play/Pause */}
<button
onClick={togglePlay}
className="text-white text-2xl hover:scale-110 transition"
>
{playing ? '⏸️' : '▶️'}
</button>
{/* Time */}
<span className="text-white text-sm">
{formatTime(currentTime)} / {formatTime(duration)}
</span>
{/* Volume */}
<div className="flex items-center gap-2">
<span className="text-white">🔊</span>
<input
type="range"
min="0"
max="1"
step="0.1"
value={volume}
onChange={handleVolumeChange}
className="w-20"
/>
</div>
<div className="flex-1" />
{/* Fullscreen */}
<button
onClick={toggleFullscreen}
className="text-white hover:scale-110 transition"
>
{fullscreen ? '⬛' : '⬜'}
</button>
</div>
</div>
)}
</div>
) }
HLS Streaming (Adaptive Bitrate) npm install hls.js
// components/HLSPlayer.tsx 'use client' import { useEffect, useRef } from 'react' import Hls from 'hls.js'
export function HLSPlayer({ src }: { src: string }) {
const videoRef = useRef
useEffect(() => { const video = videoRef.current if (!video) return
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: true,
lowLatencyMode: true
})
hls.loadSource(src)
hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log('HLS manifest loaded, quality levels:', hls.levels)
})
hls.on(Hls.Events.ERROR, (event, data) => {
console.error('HLS error:', data)
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hls.startLoad()
break
case Hls.ErrorTypes.MEDIA_ERROR:
hls.recoverMediaError()
break
default:
hls.destroy()
break
}
}
})
return () => {
hls.destroy()
}
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Native HLS support (Safari)
video.src = src
}
}, [src])
return }
Picture-in-Picture // components/PIPVideoPlayer.tsx 'use client' import { useRef, useState } from 'react'
export function PIPVideoPlayer({ src }: { src: string }) {
const videoRef = useRef
const togglePIP = async () => { if (!videoRef.current) return
try {
if (!pipActive) {
await videoRef.current.requestPictureInPicture()
setPipActive(true)
} else {
await document.exitPictureInPicture()
setPipActive(false)
}
} catch (error) {
console.error('PIP error:', error)
}
}
return (
<button
onClick={togglePIP}
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded"
>
{pipActive ? 'Exit PIP' : 'Enter PIP'}
</button>
</div>
) }
Subtitles/Captions // components/VideoWithSubtitles.tsx 'use client' export function VideoWithSubtitles() { return (
<track
kind="subtitles"
src="/subtitles/en.vtt"
srcLang="en"
label="English"
default
/>
<track
kind="subtitles"
src="/subtitles/es.vtt"
srcLang="es"
label="Español"
/>
<track
kind="subtitles"
src="/subtitles/fr.vtt"
srcLang="fr"
label="Français"
/>
</video>
) }
VTT Subtitle File:
WEBVTT
00:00:00.000 --> 00:00:02.000 Hello, welcome to our video.
00:00:02.500 --> 00:00:05.000 Today we'll learn about web development.
00:00:05.500 --> 00:00:08.000 Let's get started!
Quality Selection // components/QualitySelector.tsx 'use client' import { useState } from 'react'
const qualities = [ { label: '1080p', src: '/video-1080p.mp4' }, { label: '720p', src: '/video-720p.mp4' }, { label: '480p', src: '/video-480p.mp4' }, { label: '360p', src: '/video-360p.mp4' } ]
export function QualitySelector() { const [currentQuality, setCurrentQuality] = useState(qualities[1])
return (
<div className="mt-4">
<label className="mr-2">Quality:</label>
<select
value={currentQuality.label}
onChange={(e) => {
const quality = qualities.find(q => q.label === e.target.value)
if (quality) setCurrentQuality(quality)
}}
className="px-4 py-2 border rounded"
>
{qualities.map((q) => (
<option key={q.label} value={q.label}>
{q.label}
</option>
))}
</select>
</div>
</div>
) }
Playback Speed Control // components/PlaybackSpeed.tsx 'use client' import { useRef, useState } from 'react'
const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2]
export function PlaybackSpeed({ src }: { src: string }) {
const videoRef = useRef
const handleSpeedChange = (newSpeed: number) => { setSpeed(newSpeed) if (videoRef.current) { videoRef.current.playbackRate = newSpeed } }
return (
<div className="mt-4 flex gap-2">
<span>Speed:</span>
{speeds.map((s) => (
<button
key={s}
onClick={() => handleSpeedChange(s)}
className={`px-3 py-1 rounded ${
speed === s ? 'bg-blue-600 text-white' : 'bg-gray-200'
}`}
>
{s}x
</button>
))}
</div>
</div>
) }
Video Thumbnail on Hover // components/VideoThumbnailPreview.tsx 'use client' import { useState } from 'react'
export function VideoThumbnailPreview({ videoSrc }: { videoSrc: string }) { const [thumbnailTime, setThumbnailTime] = useState(0)
const handleProgressHover = (e: React.MouseEvent
return (
<video src={videoSrc} controls className="w-full mt-4" />
</div>
) }
Video Upload with Progress // components/VideoUpload.tsx 'use client' import { useState } from 'react'
export function VideoUpload() {
const [uploading, setUploading] = useState(false)
const [progress, setProgress] = useState(0)
const [videoURL, setVideoURL] = useState
const handleUpload = async (e: React.ChangeEvent
setUploading(true)
setProgress(0)
const formData = new FormData()
formData.append('video', file)
const xhr = new XMLHttpRequest()
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100
setProgress(percentComplete)
}
})
xhr.addEventListener('load', () => {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText)
setVideoURL(response.url)
}
setUploading(false)
})
xhr.open('POST', '/api/upload/video')
xhr.send(formData)
}
return (
{uploading && (
<div className="mb-4">
<div className="h-2 bg-gray-200 rounded overflow-hidden">
<div
className="h-full bg-blue-600 transition-all"
style={{ width: `${progress}%` }}
/>
</div>
<p className="text-sm text-gray-600 mt-1">
Uploading: {Math.round(progress)}%
</p>
</div>
)}
{videoURL && (
<video src={videoURL} controls className="w-full" />
)}
</div>
) }
When to Use Me
Perfect for:
Building video platforms Adding video content Implementing video streaming Creating video courses Building video players
I'll help you:
Build custom video players Implement HLS streaming Add subtitles/captions Support multiple qualities Handle video uploads What I'll Create 🎥 Custom Video Players 📺 HLS/Adaptive Streaming 📝 Subtitles & Captions ⚙️ Quality Selection ⏩ Playback Speed Control 🖼️ Picture-in-Picture
Let's create amazing video experiences!
← 返回排行榜