Fix MP4 mux for web playback: add faststart and genpts
Some checks are pending
GPU Worker CI/CD / test (push) Waiting to run
GPU Worker CI/CD / deploy (push) Blocked by required conditions

- Add -movflags +faststart to move moov atom to start
- Add -fflags +genpts for proper timestamp generation
- Fixes jerky playback and video/audio desync

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-04 00:32:45 +00:00
parent 9151d2c2a8
commit 0bd8ee71c7
3 changed files with 39 additions and 26 deletions

View File

@@ -402,25 +402,31 @@ async def get_run(
# Detect media type using magic bytes, fall back to database item_type
output_cid = run["output_cid"]
media_type = None
try:
from ..services.run_service import detect_media_type
cache_path = get_cache_manager().get_by_cid(output_cid)
if cache_path and cache_path.exists():
simple_type = detect_media_type(cache_path)
media_type = type_to_mime(simple_type)
output_media_type = media_type
except Exception:
pass
# Fall back to database item_type if local detection failed
if not media_type:
# Streaming runs (with ipfs_cid) are always video/mp4
if run.get("ipfs_cid"):
media_type = "video/mp4"
output_media_type = media_type
else:
try:
import database
item_types = await database.get_item_types(output_cid, run.get("actor_id"))
if item_types:
media_type = type_to_mime(item_types[0].get("type"))
from ..services.run_service import detect_media_type
cache_path = get_cache_manager().get_by_cid(output_cid)
if cache_path and cache_path.exists():
simple_type = detect_media_type(cache_path)
media_type = type_to_mime(simple_type)
output_media_type = media_type
except Exception:
pass
# Fall back to database item_type if local detection failed
if not media_type:
try:
import database
item_types = await database.get_item_types(output_cid, run.get("actor_id"))
if item_types:
media_type = type_to_mime(item_types[0].get("type"))
output_media_type = media_type
except Exception:
pass
artifacts.append({
"cid": output_cid,
"step_name": "Output",
@@ -568,13 +574,17 @@ async def list_runs(
for run in runs:
# Add output media info
if run.get("output_cid"):
try:
cache_path = cache_manager.get_by_cid(run["output_cid"])
if cache_path and cache_path.exists():
simple_type = detect_media_type(cache_path)
run["output_media_type"] = type_to_mime(simple_type)
except Exception:
pass
# Streaming runs (with ipfs_cid) are always video/mp4
if run.get("ipfs_cid"):
run["output_media_type"] = "video/mp4"
else:
try:
cache_path = cache_manager.get_by_cid(run["output_cid"])
if cache_path and cache_path.exists():
simple_type = detect_media_type(cache_path)
run["output_media_type"] = type_to_mime(simple_type)
except Exception:
pass
# Add input media info (first 3 inputs)
input_previews = []

View File

@@ -575,7 +575,7 @@
{# Inline media preview - prefer IPFS URLs when available #}
<div class="mb-4">
{% if output_media_type and output_media_type.startswith('image/') %}
<a href="/cache/{{ run.output_cid }}" class="block">
<a href="{% if run.ipfs_cid %}/ipfs/{{ run.ipfs_cid }}{% else %}/cache/{{ run.output_cid }}{% endif %}" class="block">
<img src="{% if run.ipfs_cid %}/ipfs/{{ run.ipfs_cid }}{% else %}/cache/{{ run.output_cid }}/raw{% endif %}" alt="Output"
class="max-w-full max-h-96 rounded-lg mx-auto">
</a>
@@ -593,14 +593,15 @@
</div>
<div class="flex items-center justify-between">
<a href="/cache/{{ run.output_cid }}" class="font-mono text-sm text-blue-400 hover:text-blue-300">
{{ run.output_cid }}
<a href="{% if run.ipfs_cid %}/ipfs/{{ run.ipfs_cid }}{% else %}/cache/{{ run.output_cid }}{% endif %}"
class="font-mono text-sm text-blue-400 hover:text-blue-300">
{% if run.ipfs_cid %}{{ run.ipfs_cid }}{% else %}{{ run.output_cid }}{% endif %}
</a>
{% if run.ipfs_cid %}
<a href="https://ipfs.io/ipfs/{{ run.ipfs_cid }}"
target="_blank"
class="text-gray-400 hover:text-white text-sm">
IPFS: {{ run.ipfs_cid[:16] }}...
View on IPFS Gateway
</a>
{% endif %}
</div>

View File

@@ -411,6 +411,8 @@ def run_stream(
"ffmpeg", "-y",
"-i", str(hls_playlist),
"-c", "copy", # Just copy streams, no re-encoding
"-movflags", "+faststart", # Move moov atom to start for web playback
"-fflags", "+genpts", # Generate proper timestamps
str(final_mp4)
]
logger.info(f"Muxing HLS to MP4: {' '.join(mux_cmd)}")