mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-12 01:36:54 +02:00
add stabilisation camera recorder
This commit is contained in:
1 parent
6add333ce6
commit
b4347d068d
2 files changed
+62
-18
No files matched your search
@@ -53,11 +53,22 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
|
||||
console.log(`📸 Starting camera: ${config.label}, facing: ${facingMode}`);
|
||||
|
||||
const constraints: MediaStreamConstraints = {
|
||||
audio: true,
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
},
|
||||
video: {
|
||||
facingMode: facingMode,
|
||||
width: { ideal: config.width, min: 640 },
|
||||
height: { ideal: config.height, min: 480 },
|
||||
frameRate: { ideal: 30 },
|
||||
// @ts-ignore - Advanced constraints for iOS stabilization
|
||||
advanced: [
|
||||
{ zoom: 1.0 },
|
||||
// Enable video stabilization on supported devices (iOS)
|
||||
{ videoStabilizationMode: 'cinematic' },
|
||||
{ videoStabilizationMode: 'auto' },
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -240,18 +251,23 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
|
||||
<X className="h-6 w-6" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-black/30 backdrop-blur-md px-3 py-1 rounded-full text-white font-mono text-sm">
|
||||
{isRecording ? formatTime(timer) : (resolutionInfo || 'Camera')}
|
||||
</div>
|
||||
{!isRecording && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
{/* Recording timer or quality selector */}
|
||||
{isRecording ? (
|
||||
<div className="bg-red-600 px-3 py-1 rounded-full text-white font-mono text-sm flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-white rounded-full animate-pulse" />
|
||||
{formatTime(timer)}
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => setShowSettings(!showSettings)}
|
||||
className="text-white"
|
||||
className="bg-black/50 backdrop-blur-md px-3 py-2 rounded-full text-white font-medium text-sm flex items-center gap-2 border border-white/30"
|
||||
>
|
||||
<Settings2 className="h-5 w-5" />
|
||||
</Button>
|
||||
<Settings2 className="h-4 w-4" />
|
||||
{quality.toUpperCase()}
|
||||
<span className="text-white/60 text-xs">
|
||||
{resolutionInfo || QUALITY_CONFIGS[quality].label}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" onClick={switchCamera} className="text-white">
|
||||
@@ -272,8 +288,8 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
|
||||
setShowSettings(false);
|
||||
}}
|
||||
className={`px-3 py-2 rounded-lg text-sm font-medium transition-all ${quality === q
|
||||
? 'bg-white text-black'
|
||||
: 'bg-white/20 text-white hover:bg-white/30'
|
||||
? 'bg-white text-black'
|
||||
: 'bg-white/20 text-white hover:bg-white/30'
|
||||
}`}
|
||||
>
|
||||
{q.toUpperCase()}
|
||||
@@ -298,7 +314,26 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="absolute bottom-0 left-0 right-0 p-8 pb-12 flex justify-center items-center bg-gradient-to-t from-black/80 to-transparent">
|
||||
<div className="absolute bottom-0 left-0 right-0 p-6 pb-10 flex flex-col items-center bg-gradient-to-t from-black/80 to-transparent">
|
||||
{/* Quality selector - visible before recording */}
|
||||
{!isRecording && (
|
||||
<div className="flex gap-2 mb-6">
|
||||
{(Object.keys(QUALITY_CONFIGS) as VideoQuality[]).map((q) => (
|
||||
<button
|
||||
key={q}
|
||||
onClick={() => setQuality(q)}
|
||||
className={`px-4 py-2 rounded-full text-sm font-bold transition-all ${quality === q
|
||||
? 'bg-white text-black'
|
||||
: 'bg-white/20 text-white border border-white/40'
|
||||
}`}
|
||||
>
|
||||
{q.toUpperCase()}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Record button */}
|
||||
{isRecording ? (
|
||||
<button
|
||||
onClick={stopRecording}
|
||||
|
||||
+13
-4
@@ -310,15 +310,22 @@ async def process_reel(request: ReelRequest, x_api_key: str = Header(None)):
|
||||
# (Original audio is never used per user request)
|
||||
|
||||
if has_music:
|
||||
# Music volume
|
||||
music_vol = request.music_volume * 0.4 if has_tts else request.music_volume
|
||||
# Music volume - ensure it's properly scaled (0.0 to 1.0)
|
||||
# Apply volume more aggressively for noticeable effect
|
||||
music_vol = request.music_volume
|
||||
if has_tts:
|
||||
# Reduce music even more when TTS is active so voice is clear
|
||||
music_vol = music_vol * 0.3
|
||||
print(
|
||||
f"🎵 Music volume applied: {music_vol:.2f} (requested: {request.music_volume})"
|
||||
)
|
||||
filter_complex_parts.append(f"[1:a]volume={music_vol}[a1]")
|
||||
mix_inputs += 1
|
||||
|
||||
if has_tts:
|
||||
tts_idx = 2 if has_music else 1
|
||||
# Voice needs to be loud and clear
|
||||
filter_complex_parts.append(f"[{tts_idx}:a]volume=2.0[a2]")
|
||||
filter_complex_parts.append(f"[{tts_idx}:a]volume=1.5[a2]")
|
||||
mix_inputs += 1
|
||||
|
||||
# Build mix command
|
||||
@@ -330,8 +337,10 @@ async def process_reel(request: ReelRequest, x_api_key: str = Header(None)):
|
||||
if has_tts:
|
||||
inputs_str += "[a2]"
|
||||
|
||||
# IMPORTANT: normalize=0 prevents amix from auto-adjusting volumes
|
||||
# which was causing volume slider to have no effect
|
||||
filter_complex_parts.append(
|
||||
f"{inputs_str}amix=inputs={mix_inputs}:duration=first:dropout_transition=2[aout]"
|
||||
f"{inputs_str}amix=inputs={mix_inputs}:duration=first:dropout_transition=2:normalize=0[aout]"
|
||||
)
|
||||
|
||||
cmd.extend(["-filter_complex", ";".join(filter_complex_parts)])
|
||||
|
||||
Reference in new issue
Block a user