- 在VideoUtils中新增ffmpeg_concat_medias_video_only函数,仅处理视频流忽略音频 - 新增concat_medias_video_only.py模块,提供Modal函数封装 - 在ffmpeg路由中新增/concat-video-only接口 - 解决音频流缺失导致的"Stream specifier ':a' matches no streams"错误 - 适用于不需要音频的视频拼接场景
52 lines
3.0 KiB
Python
52 lines
3.0 KiB
Python
import modal
|
|
|
|
from ..ffmpeg_app import ffmpeg_worker_image, app, config, s3_mount, local_copy_to_s3, output_path_prefix
|
|
|
|
with ffmpeg_worker_image.imports():
|
|
from BowongModalFunctions.models.requests.models import MediaSourcesRequest
|
|
from BowongModalFunctions.models.ffmpeg_tasks.models import SentryTransactionInfo, WebhookNotify, FFMPEGResult
|
|
from BowongModalFunctions.utils.PathUtils import FileUtils
|
|
from BowongModalFunctions.utils.SentryUtils import SentryUtils
|
|
from BowongModalFunctions.utils.VideoUtils import VideoUtils
|
|
import sentry_sdk
|
|
from typing import Optional, Tuple
|
|
from modal import current_function_call_id
|
|
|
|
|
|
@app.function(
|
|
timeout=1800,
|
|
cloud="aws",
|
|
# region='ap-northeast',
|
|
max_containers=config.ffmpeg_worker_concurrency,
|
|
volumes={
|
|
s3_mount: modal.CloudBucketMount(
|
|
bucket_name=config.S3_bucket_name,
|
|
secret=modal.Secret.from_name("aws-s3-secret",
|
|
environment_name=config.modal_environment),
|
|
),
|
|
}, )
|
|
@modal.concurrent(max_inputs=1)
|
|
async def ffmpeg_concat_medias_video_only(medias: MediaSourcesRequest,
|
|
sentry_trace: Optional[SentryTransactionInfo] = None,
|
|
webhook: Optional[WebhookNotify] = None) -> Tuple[
|
|
FFMPEGResult, Optional[SentryTransactionInfo]]:
|
|
fn_id = current_function_call_id()
|
|
|
|
@SentryUtils.sentry_tracker(name="视频合并任务(仅视频流)", op="ffmpeg.concat_video_only", fn_id=fn_id,
|
|
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
|
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
|
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
|
async def ffmpeg_process(media_sources: MediaSourcesRequest, output_filepath: str) -> FFMPEGResult:
|
|
input_videos = [f"{s3_mount}/{media_source.cache_filepath}" for media_source in media_sources.inputs]
|
|
local_output_path, metadata = await VideoUtils.ffmpeg_concat_medias_video_only(media_paths=input_videos,
|
|
output_path=output_filepath)
|
|
s3_outputs = local_copy_to_s3([local_output_path])
|
|
return FFMPEGResult(urn=s3_outputs[0], metadata=metadata,
|
|
content_length=FileUtils.get_file_size(local_output_path), )
|
|
|
|
output_path = f"{output_path_prefix}/{config.modal_environment}/concat_video_only/outputs/{fn_id}/output.mp4"
|
|
result = await ffmpeg_process(media_sources=medias, output_filepath=output_path)
|
|
if not sentry_trace:
|
|
sentry_trace = SentryTransactionInfo(x_trace_id=sentry_sdk.get_traceparent(),
|
|
x_baggage=sentry_sdk.get_baggage())
|
|
return result, sentry_trace |