|
1 | 1 | import io |
| 2 | +import os |
2 | 3 | import tempfile |
| 4 | +import threading |
3 | 5 |
|
4 | 6 | import av |
5 | 7 | import requests |
@@ -55,3 +57,42 @@ def stream_video_from_bytes(bytes_iterator): |
55 | 57 | reader = io.BufferedReader(buffer) |
56 | 58 | container = av.open(reader) |
57 | 59 | yield from container.decode(video=0) |
| 60 | + |
| 61 | + |
| 62 | +def recontain_as_streamable(filepath): |
| 63 | + return recontain(filepath, "mpegts", {"muxpreload": "0", "muxdelay": "0"}) |
| 64 | + |
| 65 | + |
| 66 | +def recontain(input, format, options={}): |
| 67 | + # pyav-only implementation of "ffmpeg -i filepath -f mpegts -muxpreload 0 -muxdelay 0 pipe:" |
| 68 | + read_pipe_fd, write_pipe_fd = os.pipe() |
| 69 | + read_pipe = os.fdopen(read_pipe_fd, "rb") |
| 70 | + write_pipe = os.fdopen(write_pipe_fd, "wb") |
| 71 | + |
| 72 | + def _run_av(): |
| 73 | + input_container = output_container = None |
| 74 | + try: |
| 75 | + # open input and output containers, using mpegts as output format |
| 76 | + input_container = av.open(input, options=options) |
| 77 | + output_container = av.open(write_pipe, mode="w", format=format) |
| 78 | + |
| 79 | + # Copy streams directly without re-encoding |
| 80 | + for stream in input_container.streams: |
| 81 | + output_container.add_stream_from_template(stream) |
| 82 | + |
| 83 | + # Read packets from input and write them to output |
| 84 | + for packet in input_container.demux(): |
| 85 | + if not packet.size: |
| 86 | + break |
| 87 | + output_container.mux(packet) |
| 88 | + |
| 89 | + finally: |
| 90 | + if output_container: |
| 91 | + output_container.close() |
| 92 | + if input_container: |
| 93 | + input_container.close() |
| 94 | + |
| 95 | + t = threading.Thread(target=_run_av) |
| 96 | + t.start() |
| 97 | + |
| 98 | + return read_pipe |
0 commit comments