167AliRaza commited on
Commit
d6f16cc
·
verified ·
1 Parent(s): 3ab5773

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -24
app.py CHANGED
@@ -7,28 +7,65 @@ import io
7
 
8
  app = FastAPI()
9
 
10
- def process_video(input_bytes, speed=1.5):
11
- """
12
- Process video to change playback speed and compress.
13
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_input:
15
- tmp_input.write(input_bytes)
16
  input_path = tmp_input.name
17
 
18
  output_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
19
 
 
 
 
 
 
 
 
 
 
20
  video_speed = 1 / speed
21
- audio_speed = speed
 
 
 
 
 
 
22
 
23
  cmd = [
24
  "ffmpeg", "-i", input_path,
25
- "-filter_complex", f"[0:v]setpts={video_speed}*PTS[v];[0:a]atempo={audio_speed}[a]",
26
- "-map", "[v]", "-map", "[a]",
 
 
 
 
 
 
27
  "-vcodec", "libx264", "-crf", "28", "-preset", "fast",
28
  "-movflags", "+faststart",
29
  "-y", output_path
30
  ]
31
 
 
32
  process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
33
  process.wait()
34
 
@@ -37,28 +74,15 @@ def process_video(input_bytes, speed=1.5):
37
  os.remove(output_path)
38
  raise HTTPException(status_code=500, detail="Video processing failed.")
39
 
 
40
  with open(output_path, "rb") as f:
41
- output_data = f.read()
42
 
43
  os.remove(input_path)
44
  os.remove(output_path)
45
 
46
- return output_data
47
-
48
-
49
- @app.post("/process_video")
50
- async def upload_video(file: UploadFile = File(...), speed: float = 1.5):
51
- """
52
- Upload a video file and return processed video.
53
- """
54
- if not (0.25 <= speed <= 4.0):
55
- raise HTTPException(status_code=400, detail="Speed must be between 0.25x and 4x.")
56
-
57
- video_bytes = await file.read()
58
- processed_video = process_video(video_bytes, speed)
59
-
60
  return StreamingResponse(
61
- io.BytesIO(processed_video),
62
  media_type="video/mp4",
63
  headers={"Content-Disposition": "attachment; filename=processed_video.mp4"}
64
  )
 
7
 
8
  app = FastAPI()
9
 
10
+ def build_atempo_filter(speed: float) -> str:
11
+ """Build a valid FFmpeg atempo chain for any 0.25–4.0 speed."""
12
+ filters = []
13
+ while speed > 2.0:
14
+ filters.append("atempo=2.0")
15
+ speed /= 2.0
16
+ while speed < 0.5:
17
+ filters.append("atempo=0.5")
18
+ speed *= 2.0
19
+ filters.append(f"atempo={speed}")
20
+ return ",".join(filters)
21
+
22
+ @app.post("/process_video")
23
+ async def process_video_endpoint(file: UploadFile = File(...), speed: float = 1.5):
24
+ if not (0.25 <= speed <= 4.0):
25
+ raise HTTPException(status_code=400, detail="Speed must be between 0.25x and 4x.")
26
+
27
+ # Save uploaded file
28
+ video_bytes = await file.read()
29
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_input:
30
+ tmp_input.write(video_bytes)
31
  input_path = tmp_input.name
32
 
33
  output_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
34
 
35
+ # Check if input has audio
36
+ probe_audio = subprocess.run(
37
+ ["ffprobe", "-v", "error", "-select_streams", "a",
38
+ "-show_entries", "stream=codec_type", "-of", "csv=p=0", input_path],
39
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
40
+ )
41
+ has_audio = bool(probe_audio.stdout.strip())
42
+
43
+ # Build filters
44
  video_speed = 1 / speed
45
+ filters = [f"[0:v]setpts={video_speed}*PTS[v]"]
46
+
47
+ if has_audio:
48
+ audio_filter = build_atempo_filter(speed)
49
+ filters.append(f"[0:a]{audio_filter}[a]")
50
+
51
+ filter_complex = ";".join(filters)
52
 
53
  cmd = [
54
  "ffmpeg", "-i", input_path,
55
+ "-filter_complex", filter_complex,
56
+ "-map", "[v]"
57
+ ]
58
+
59
+ if has_audio:
60
+ cmd += ["-map", "[a]"]
61
+
62
+ cmd += [
63
  "-vcodec", "libx264", "-crf", "28", "-preset", "fast",
64
  "-movflags", "+faststart",
65
  "-y", output_path
66
  ]
67
 
68
+ # Run ffmpeg
69
  process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
70
  process.wait()
71
 
 
74
  os.remove(output_path)
75
  raise HTTPException(status_code=500, detail="Video processing failed.")
76
 
77
+ # Return file
78
  with open(output_path, "rb") as f:
79
+ processed_data = f.read()
80
 
81
  os.remove(input_path)
82
  os.remove(output_path)
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  return StreamingResponse(
85
+ io.BytesIO(processed_data),
86
  media_type="video/mp4",
87
  headers={"Content-Disposition": "attachment; filename=processed_video.mp4"}
88
  )