如何将数据从Python异步套接字服务器发送到子进程?

杜加尔公爵

Python 3.6

该程序:

  1. 启动ffmpeg作为子进程
  2. 等待套接字连接
  3. 在套接字上接收PNG图像
  4. 将PNG图像发送到ffmpeg stdin

问题是步骤4。我不知道如何从协程向ffmpeg子进程的stdin发送接收到的PNG图像。谁能指出我的正确方向,以将PNG图像发送到ffmpeg子进程的stdin?

编辑:澄清-此代码没有任何问题,它可以在套接字上接收PNG。我只是不知道如何将PNG发送到ffmpeg的stdin中。我已经做过很多Python了,但是asyncio对我来说是陌生的,如何将它们联系在一起是一个谜。

谢谢!

import asyncio
import argparse, sys
import sys
import base64
from struct import unpack

parser = argparse.ArgumentParser()
parser.add_argument('--port', help='ffmpeg listen port')
parser.add_argument('--outputfilename', help='ffmpeg output filename')
args = parser.parse_args()
if not args.port:
    print("port is required")
    sys.exit(1)
if not args.outputfilename:
    print("outputfilename is required")
    sys.exit(1)

async def _read_stream(stream, cb):
    while True:
        line = await stream.readline()
        if line:
            cb(line)
        else:
            break

async def _stream_subprocess(cmd, stdout_cb, stderr_cb):
    process = await asyncio.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        stdin=asyncio.subprocess.PIPE,
    )

    await asyncio.wait([
        _read_stream(process.stdout, stdout_cb),
        _read_stream(process.stderr, stderr_cb)
    ])
    return await process.wait()


def process_stderr(line):
    # ffmpeg finishes processing and writes the output file when its input is closed
    # thus the completion message will come out of stderr only when the socket or stdin or whatever is closed
    line = line.decode()
    print(line)
    if "Output" in line:
        if args.outputfilename in line:
            print('finished!!!!')
            sys.exit(0)

def process_stdout(line):
    print("STDOUT: %s" % line)

def spawn_ffmpeg(listenport, outputfilename, framerate=30, format='webm'):
    outputdirectory = "sftp://username:[email protected]/var/www/static/"
    input_type = "pipe:0" #stdin

    params = \
        f"ffmpeg  " \
        f"-loglevel 56 " \
        f"-y -framerate {framerate} " \
        f"-f image2pipe " \
        f"-i {input_type} " \
        f"-c:v libvpx-vp9 " \
        f"-b:v 1024k " \
        f"-q:v 0 " \
        f"-pix_fmt yuva420p " \
        f"{outputdirectory}{outputfilename} "

    return params


async def socket_png_receiver(reader, writer):
    while True:
        # first the client sends the length of the data to us
        lengthbuf = await reader.read(4)
        length, = unpack('!I', lengthbuf)
        if length == 0:
            print("length was 0, finish") # a zero length PNG says that there are no more frames
            break
        # then we read the PNG
        data = await reader.read(length)
        data = data.decode() # from bytes to string
        png_bytes = base64.b64decode(data) # from base64 to bytes
        # next line was just a guess, so I have commented it out.
        #await proc.communicate(png_bytes)
        print("Got PNG, length", length)
    return


loop = asyncio.get_event_loop()
command = spawn_ffmpeg("24897", args.outputfilename)
ffmpeg_process = _stream_subprocess(
    command.split(),
    process_stdout,
    process_stderr,
)
#coro = asyncio.start_server(socket_png_receiver, '0.0.0.0', args.port, ffmpeg_process, loop=loop)
coro = asyncio.start_server(socket_png_receiver, '0.0.0.0', args.port, loop=loop)
several_futures = asyncio.gather(ffmpeg_process, coro)
server = loop.run_until_complete(several_futures)
server.close()
loop.close()

这是@ user4815162342建议的更改

import asyncio
import argparse, sys
import sys
import base64
from struct import unpack

parser = argparse.ArgumentParser()
parser.add_argument('--port', help='ffmpeg listen port')
parser.add_argument('--outputfilename', help='ffmpeg output filename')
args = parser.parse_args()
if not args.port:
    print("port is required")
    sys.exit(1)
if not args.outputfilename:
    print("outputfilename is required")
    sys.exit(1)
if not args.outputfilename.endswith('.webm'):
    print("outputfilename must end with '.webm'")
    sys.exit(1)

async def _read_stream(stream, cb):
    while True:
        line = await stream.readline()
        if line:
            cb(line)
        else:
            break


async def _stream_subprocess(cmd, stdout_cb, stderr_cb):
    global process
    process = await asyncio.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        stdin=asyncio.subprocess.PIPE,
    )

    await asyncio.wait([
        _read_stream(process.stdout, stdout_cb),
        _read_stream(process.stderr, stderr_cb)
    ])
    return await process.wait()


def process_stderr(line):
    # ffmpeg finishes processing and writes the output file when its input is closed
    # thus the completion message will come out of stderr only when the socket or stdin or whatever is closed
    line = line.decode()
    print(line)
    if "Output" in line:
        if args.outputfilename in line:
            print('finished!!!!')
            sys.exit(0)


def process_stdout(line):
    print("STDOUT: %s" % line)


def spawn_ffmpeg(listenport, outputfilename, framerate=30, format='webm'):
    outputdirectory = "sftp://username:[email protected]/var/www/static/"
    input_type = "pipe:0"  # stdin

    params = \
        f"ffmpeg  " \
        f"-loglevel 56 " \
        f"-y " \
        f"-framerate {framerate} " \
        f"-i {input_type} " \
        f"{outputdirectory}{outputfilename} "

    print(params)
    return params


async def socket_png_receiver(reader, writer):
    while True:
        # first the client sends the length of the data to us
        lengthbuf = await reader.readexactly(4)
        length, = unpack('!I', lengthbuf)
        if length == 0:
            print("length was 0, finish")  # a zero length PNG says that there are no more frames
            break
        # then we read the PNG
        print("Got PNG, length", length)
        data = await reader.readexactly(length)
        print(data)
        png_bytes = base64.b64decode(data)  # from base64 to bytes
        process.stdin.write(png_bytes)
    return


loop = asyncio.get_event_loop()
command = spawn_ffmpeg("24897", args.outputfilename)
ffmpeg_process = _stream_subprocess(
    command.split(),
    process_stdout,
    process_stderr,
)
coro = asyncio.start_server(socket_png_receiver, '0.0.0.0', args.port, loop=loop)
several_futures = asyncio.gather(ffmpeg_process, coro)
server = loop.run_until_complete(several_futures)
server.close()
loop.close()
用户名

该代码有几个问题:

  • await reader.read(length)应该是await reader.readexactly(length)因为to的参数StreamReader.read要读取最大字节数,并且它可以返回的字节数更少。

  • proc.communicate(png_bytes)应该更改为proc.stdin.write(png_bytes)communicate()此处的to调用不正确,因为您要在communicate()等待所有流关闭的同时继续与程序对话

  • asyncio.create_subprocess_exec(...)必须通过提供返回的流程实例socket_png_receiver,例如,process使用变量全局化global process(最好使用一个类并分配给self.process,但这超出了此答案的范围。)

一些潜在的问题:

  • 不需要data从字节解码为字符串,base64.b64decode可以接受字节就可以了。

  • spawn_ffmpeg()似乎没有使用其listenport参数。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将套接字从Android发送到Python服务器

我需要服务器将消息发送到所有客户端(Python,套接字)

如何将数据从服务器发送到Android?

如何将数据从android发送到mysql服务器?

如何将组件数据作为json发送到服务器?

使用套接字将数据从Python(客户端)发送到C ++(服务器)数组

将数据从Python发送到带有套接字的服务器节点(NodeJS,Socket.io)

如何将“数据”和“结束”事件从cURL发送到nodejs的HTTP服务器?

使用套接字将数据发送到远程服务器

如何将表格数据发送到服务器

如何将客户端数据发送到服务器端

FTP服务器未通过套接字将数据发送到Python中的代理

如何将boost asio tcp套接字传递给线程以将心跳发送到客户端或服务器

尝试在Python套接字中将数据从服务器发送到客户端时出现管道错误

使用python套接字将Txt文件从客户端发送到服务器

如何将所有SQLite数据发送到在线服务器

Python套接字-将数据包发送到服务器并等待响应

Java套接字-将数据从服务器发送到客户端

将数据从Python TCP套接字(作为服务器)发送到JS客户端

如何将String数组作为发布数据发送到Web服务器?

如何将多个json对象的数据发送到android中的服务器?

如何将HTML表单数据发送到Java http服务器

Java套接字-将数据从客户端发送到服务器

通过Android上的套接字将虚拟数据发送到Java服务器

将数据从Web服务器发送到Perl套接字侦听器

远程Internet服务器如何将数据包发送到本地IP?

React 和 NodeJS:如何将数据从服务器发送到客户端?

如何使用 Python 将数据从客户端套接字发送到服务器套接字?

如何使用套接字将 2 个变量同时从客户端发送到服务器 [Python]