Properly take advantage of HW accel

This commit is contained in:
Nexus 2024-04-15 22:28:38 +01:00
parent e70056f2ff
commit 751287479a
Signed by: nex
GPG key ID: 0FA334385D0B689F

View file

@ -2,6 +2,7 @@ import asyncio
import pathlib import pathlib
import subprocess import subprocess
import aiohttp
import discord import discord
import re import re
import tempfile import tempfile
@ -66,37 +67,67 @@ class AutoResponder(commands.Cog):
else: else:
self.log.info("No HEVC streams found in %s", uri) self.log.info("No HEVC streams found in %s", uri)
return return
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp: extension = pathlib.Path(uri).suffix
tmp_path = pathlib.Path(tmp.name) with tempfile.NamedTemporaryFile(suffix=extension) as tmp_dl:
self.log.info("Transcoding %r to %r", uri, tmp_path) self.log.info("Downloading %r to %r", uri, tmp_dl.name)
args = [ async with aiohttp.ClientSession(
"-i", str(uri), headers={
"-c:v", "libx264", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,"
"-crf", "25", "*/*;q=0.8",
"-c:a", "libopus", "Accept-Language": "en-US,en;q=0.5",
"-b:a", "64k", "Sec-Fetch-Dest": "document",
"-preset", "slower", "Sec-Fetch-Mode": "navigate",
"-y" "Sec-Fetch-Site": "none",
] "Sec-Fetch-User": "?1",
process = await asyncio.create_subprocess_exec( "Sec-Gpc": "1",
"ffmpeg", "Upgrade-Insecure-Requests": "1",
*args, "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0",
str(tmp_path), }
stdout=asyncio.subprocess.PIPE, ) as session:
stderr=asyncio.subprocess.PIPE, async with session.get(uri) as resp:
) resp.raise_for_status()
stdout, stderr = await process.communicate() async for chunk in resp.content.iter_any():
self.log.info("finished transcode with return code %d", process.returncode) # noinspection PyTypeChecker
self.log.debug("stdout: %r", stdout.decode) tmp_dl.write(chunk)
self.log.debug("stderr: %r", stderr.decode) self.log.info("Finished downloading %r to %r", uri, tmp_dl.name)
if process.returncode != 0:
raise subprocess.SubprocessError( with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
process.returncode, tmp_path = pathlib.Path(tmp.name)
" ".join(args), self.log.info("Transcoding %r to %r", uri, tmp_path)
stdout, args = [
stderr, "-hide_banner",
"-hwaccel", "auto",
"-i", tmp_dl.name,
"-c:v", "libx264",
"-crf", "25",
"-c:a", "libopus",
"-b:a", "64k",
"-preset", "faster",
"-vsync", "2",
"-pix_fmt", "yuv420p",
"-movflags", "faststart",
"-profile:v", "main",
"-y"
]
process = await asyncio.create_subprocess_exec(
"ffmpeg",
*args,
str(tmp_path),
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
) )
return discord.File(tmp_path), tmp_path stdout, stderr = await process.communicate()
self.log.info("finished transcode with return code %d", process.returncode)
self.log.debug("stdout: %r", stdout.decode)
self.log.debug("stderr: %r", stderr.decode)
if process.returncode != 0:
raise subprocess.SubprocessError(
process.returncode,
" ".join(args),
stdout,
stderr,
)
return discord.File(tmp_path), tmp_path
@commands.Cog.listener("on_message") @commands.Cog.listener("on_message")
async def auto_responder(self, message: discord.Message): async def auto_responder(self, message: discord.Message):
@ -104,33 +135,45 @@ class AutoResponder(commands.Cog):
return return
# Check for HEVC truth social links and convert into h264 # Check for HEVC truth social links and convert into h264
links = self.extract_links(message.content, "static-assets-1.truthsocial.com") if message.channel.name == "spam" and message.author.id in {1101439218334576742, 1229496078726860921}:
if links: links = self.extract_links(message.content, "static-assets-1.truthsocial.com")
for link in links: if links:
if link.lower().endswith( for link in links:
(".mp4", ".mov", ".qtff", ".mkv", ".asf", ".avi", ".mxf", ".ps", ".ts", ".3gp", ".3g2") hevc_containers = {
): ".mp4",
# All containers allowed to contain HEVC ".mov",
".qtff",
".mkv",
".asf",
".avi",
".mxf",
".ps",
".ts",
".3gp",
".3g2"
}
# ^ All containers allowed to contain HEVC
# per https://en.wikipedia.org/wiki/Comparison_of_video_container_formats # per https://en.wikipedia.org/wiki/Comparison_of_video_container_formats
self.log.info("Found link to transcode: %r", link) if link.lower().endswith(tuple(hevc_containers)):
try: self.log.info("Found link to transcode: %r", link)
async with message.channel.typing(): try:
_r = await self._transcode_hevc_to_h264(link) async with message.channel.typing():
if not _r: _r = await self._transcode_hevc_to_h264(link)
continue if not _r:
file, _p = _r continue
if file: file, _p = _r
if _p.stat().st_size <= 24.5 * 1024 * 1024: if file:
await message.reply(file=file) if _p.stat().st_size <= 24.5 * 1024 * 1024:
else: await message.reply(file=file)
self.log.warning( else:
"Transcoded file too large: %r (%.2f)MB", self.log.warning(
_p, "Transcoded file too large: %r (%.2f)MB",
_p.stat().st_size / 1024 / 1024 _p,
) _p.stat().st_size / 1024 / 1024
_p.unlink() )
except Exception as e: _p.unlink()
self.log.error("Failed to transcode %r: %r", link, e) except Exception as e:
self.log.error("Failed to transcode %r: %r", link, e)
def setup(bot): def setup(bot):