commit
6b48bd52b5
@ -0,0 +1,10 @@ |
|||||||
|
*.webm |
||||||
|
*.mp4 |
||||||
|
Dash/* |
||||||
|
chunk/* |
||||||
|
.venv |
||||||
|
*.flv |
||||||
|
*.jpg |
||||||
|
*.mpd |
||||||
|
*.m4s |
||||||
|
*.pyd |
@ -0,0 +1,8 @@ |
|||||||
|
# Default ignored files |
||||||
|
/shelf/ |
||||||
|
/workspace.xml |
||||||
|
# Datasource local storage ignored files |
||||||
|
/dataSources/ |
||||||
|
/dataSources.local.xml |
||||||
|
# Editor-based HTTP Client requests |
||||||
|
/httpRequests/ |
@ -0,0 +1,26 @@ |
|||||||
|
<component name="InspectionProjectProfileManager"> |
||||||
|
<profile version="1.0"> |
||||||
|
<option name="myName" value="Project Default" /> |
||||||
|
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true"> |
||||||
|
<Languages> |
||||||
|
<language minSize="62" name="Python" /> |
||||||
|
</Languages> |
||||||
|
</inspection_tool> |
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true"> |
||||||
|
<option name="ignoredPackages"> |
||||||
|
<value> |
||||||
|
<list size="1"> |
||||||
|
<item index="0" class="java.lang.String" itemvalue="python-snap7" /> |
||||||
|
</list> |
||||||
|
</value> |
||||||
|
</option> |
||||||
|
</inspection_tool> |
||||||
|
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true"> |
||||||
|
<option name="ignoredErrors"> |
||||||
|
<list> |
||||||
|
<option value="N806" /> |
||||||
|
</list> |
||||||
|
</option> |
||||||
|
</inspection_tool> |
||||||
|
</profile> |
||||||
|
</component> |
@ -0,0 +1,6 @@ |
|||||||
|
<component name="InspectionProjectProfileManager"> |
||||||
|
<settings> |
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" /> |
||||||
|
<version value="1.0" /> |
||||||
|
</settings> |
||||||
|
</component> |
@ -0,0 +1,4 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (tryCanvas)" project-jdk-type="Python SDK" /> |
||||||
|
</project> |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="ProjectModuleManager"> |
||||||
|
<modules> |
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/tryCanvas.iml" filepath="$PROJECT_DIR$/.idea/tryCanvas.iml" /> |
||||||
|
</modules> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,10 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<module type="PYTHON_MODULE" version="4"> |
||||||
|
<component name="NewModuleRootManager"> |
||||||
|
<content url="file://$MODULE_DIR$"> |
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" /> |
||||||
|
</content> |
||||||
|
<orderEntry type="jdk" jdkName="Python 3.8 (tryCanvas)" jdkType="Python SDK" /> |
||||||
|
<orderEntry type="sourceFolder" forTests="false" /> |
||||||
|
</component> |
||||||
|
</module> |
@ -0,0 +1,31 @@ |
|||||||
|
import time |
||||||
|
from datetime import datetime |
||||||
|
from threading import Thread |
||||||
|
|
||||||
|
from PIL import Image |
||||||
|
from PIL import ImageDraw, ImageFont |
||||||
|
|
||||||
|
from VideoFile import VideoFile |
||||||
|
|
||||||
|
|
||||||
|
class StreamMerger(Thread): |
||||||
|
img = None |
||||||
|
|
||||||
|
def run(self) -> None: |
||||||
|
video = VideoFile("yiv3.webm") |
||||||
|
video2 = VideoFile("supernatural.webm") |
||||||
|
video.open() |
||||||
|
video2.open() |
||||||
|
start_time = time.time() |
||||||
|
while True: |
||||||
|
img = Image.new('RGB', (1920, 1080), color='black') |
||||||
|
|
||||||
|
if video.frame is not None: |
||||||
|
img.paste(video.frame) |
||||||
|
if video2.frame is not None: |
||||||
|
img.paste(video2.frame, (0, 600)) |
||||||
|
fnt = ImageFont.truetype("antonio.ttf", 40) |
||||||
|
d = ImageDraw.Draw(img) |
||||||
|
d.text((0, 1000), str(int(time.time() - start_time)), font=fnt) |
||||||
|
self.img = img |
||||||
|
time.sleep(1.0 / 1000.0) |
@ -0,0 +1,43 @@ |
|||||||
|
import time |
||||||
|
from threading import Thread |
||||||
|
|
||||||
|
import av |
||||||
|
from PIL import Image |
||||||
|
|
||||||
|
|
||||||
|
class VideoFile(Thread): |
||||||
|
file: str = "" |
||||||
|
frame: Image = None |
||||||
|
running: bool = False |
||||||
|
|
||||||
|
def __init__(self, file: str): |
||||||
|
self.file = file |
||||||
|
super().__init__() |
||||||
|
|
||||||
|
def get_frame(self): |
||||||
|
return self.frame |
||||||
|
|
||||||
|
def stop(self): |
||||||
|
self.running = False |
||||||
|
|
||||||
|
def open(self): |
||||||
|
self.running = True |
||||||
|
self.start() |
||||||
|
|
||||||
|
def run(self) -> None: |
||||||
|
container = av.open(self.file) |
||||||
|
video = container.streams.video[0] |
||||||
|
print(video.time_base) |
||||||
|
|
||||||
|
while self.running: |
||||||
|
try: |
||||||
|
for frame in container.decode(video): |
||||||
|
|
||||||
|
if self.running: |
||||||
|
self.frame = frame.to_image() |
||||||
|
else: |
||||||
|
break |
||||||
|
|
||||||
|
time.sleep(1.0 / 60) |
||||||
|
except: |
||||||
|
self.running = False |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,41 @@ |
|||||||
|
import time |
||||||
|
from datetime import datetime |
||||||
|
|
||||||
|
import av |
||||||
|
from PIL import Image |
||||||
|
from av.frame import Fraction |
||||||
|
from PIL import Image, ImageDraw, ImageFont |
||||||
|
|
||||||
|
from StreamMerger import StreamMerger |
||||||
|
from VideoFile import VideoFile |
||||||
|
|
||||||
|
container = av.open('rtmp://localhost/live', mode='w', format='flv') |
||||||
|
stream = container.add_stream('h264', framerate=60) # alibi frame rate |
||||||
|
output_audio_stream = container.add_stream('aac', rate=44100) |
||||||
|
|
||||||
|
stream.width = 1920 |
||||||
|
stream.height = 1080 |
||||||
|
stream.pix_fmt = 'yuv420p' |
||||||
|
# stream.bit_rate = 128000 |
||||||
|
stream.time_base = Fraction(1, 60) |
||||||
|
|
||||||
|
st = StreamMerger() |
||||||
|
st.start() |
||||||
|
my_pts = 0 # [seconds] |
||||||
|
frame_i = 0 |
||||||
|
time_start = time.time() |
||||||
|
while True: |
||||||
|
if st.img is not None: |
||||||
|
frame = av.VideoFrame.from_image(st.img) |
||||||
|
framen = frame.reformat(format='yuv420p') |
||||||
|
|
||||||
|
ntime = time.time() - time_start |
||||||
|
|
||||||
|
frame.pts = ntime * 60 |
||||||
|
frame.time_base = Fraction(1, 60) |
||||||
|
# frame.key_frame = frame_i |
||||||
|
frame_i += 1 |
||||||
|
# print(dir(frame)) |
||||||
|
for packet in stream.encode(framen): |
||||||
|
container.mux(packet) |
||||||
|
time.sleep(1.0 / 60.0) |
@ -0,0 +1,3 @@ |
|||||||
|
av |
||||||
|
pillow |
||||||
|
aiortc |
@ -0,0 +1,37 @@ |
|||||||
|
#!/bin/bash |
||||||
|
#HLS, Dash and fallback code from zazu.berlin 2020, Version 20200424 |
||||||
|
|
||||||
|
VIDEO_IN=rtmp://localhost/live |
||||||
|
VIDEO_OUT=master |
||||||
|
HLS_TIME=4 |
||||||
|
FPS=25 |
||||||
|
GOP_SIZE=100 |
||||||
|
PRESET_P=veryslow |
||||||
|
V_SIZE_1=960x540 |
||||||
|
V_SIZE_2=416x234 |
||||||
|
V_SIZE_3=640x360 |
||||||
|
V_SIZE_4=768x432 |
||||||
|
V_SIZE_5=1280x720 |
||||||
|
V_SIZE_6=1920x1080 |
||||||
|
|
||||||
|
|
||||||
|
# DASH |
||||||
|
ffmpeg -i $VIDEO_IN -y \ |
||||||
|
-preset $PRESET_P -keyint_min $GOP_SIZE -g $GOP_SIZE -sc_threshold 0 -r $FPS -c:v libx264 -pix_fmt yuv420p \ |
||||||
|
-map v:0 -s:0 $V_SIZE_1 -b:v:0 2M -maxrate:0 2.14M -bufsize:0 3.5M \ |
||||||
|
-map v:0 -s:1 $V_SIZE_2 -b:v:1 145k -maxrate:1 155k -bufsize:1 220k \ |
||||||
|
-map v:0 -s:2 $V_SIZE_3 -b:v:2 365k -maxrate:2 390k -bufsize:2 640k \ |
||||||
|
-map v:0 -s:3 $V_SIZE_4 -b:v:3 730k -maxrate:3 781k -bufsize:3 1278k \ |
||||||
|
-map v:0 -s:4 $V_SIZE_4 -b:v:4 1.1M -maxrate:4 1.17M -bufsize:4 2M \ |
||||||
|
-map v:0 -s:5 $V_SIZE_5 -b:v:5 3M -maxrate:5 3.21M -bufsize:5 5.5M \ |
||||||
|
-map v:0 -s:6 $V_SIZE_5 -b:v:6 4.5M -maxrate:6 4.8M -bufsize:6 8M \ |
||||||
|
-map v:0 -s:7 $V_SIZE_6 -b:v:7 6M -maxrate:7 6.42M -bufsize:7 11M \ |
||||||
|
-map v:0 -s:8 $V_SIZE_6 -b:v:8 7.8M -maxrate:8 8.3M -bufsize:8 14M \ |
||||||
|
-init_seg_name init\$RepresentationID\$.\$ext\$ -media_seg_name chunk\$RepresentationID\$-\$Number%05d\$.\$ext\$ \ |
||||||
|
-use_template 1 -use_timeline 1 \ |
||||||
|
-seg_duration 4 -adaptation_sets "id=0,streams=v id=1,streams=a" \ |
||||||
|
-f dash Dash/dash.mpd |
||||||
|
|
||||||
|
# Fallback video file |
||||||
|
ffmpeg -i $VIDEO_IN -y -c:v libx264 -pix_fmt yuv420p -r $FPS -s $V_SIZE_1 -b:v 1.8M -c:a aac -b:a 128k -ac 1 -ar 44100 fallback-video-$V_SIZE_1.mp4 |
||||||
|
|
@ -0,0 +1,46 @@ |
|||||||
|
import av |
||||||
|
from av.filter import Graph |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
input_container = av.open('supernatural.webm', mode='r') |
||||||
|
input_container2 = av.open('yiv3.webm', mode='r') |
||||||
|
input_video_stream = input_container.streams.video[0] |
||||||
|
|
||||||
|
output_container = av.open("out.mp4", "w") |
||||||
|
output_audio_stream = output_container.add_stream('aac', rate=input_container2.streams.audio[0].base_rate) |
||||||
|
|
||||||
|
graph = Graph() |
||||||
|
|
||||||
|
in_src = graph.add_abuffer(template=input_container.streams.audio[0]) |
||||||
|
in_src2 = graph.add_abuffer(template=input_container2.streams.audio[0]) |
||||||
|
pad = graph.add("amix", "inputs=2:duration=longest") |
||||||
|
print(dir(pad)) |
||||||
|
in_src.link_to(pad, 0, 0) |
||||||
|
in_src2.link_to(pad, 0, 1) |
||||||
|
sink = graph.add('abuffersink') |
||||||
|
pad.link_to(sink) |
||||||
|
graph.configure() |
||||||
|
|
||||||
|
for frame in input_container.decode(audio=0): |
||||||
|
in_src.push(frame) |
||||||
|
|
||||||
|
for frame in input_container2.decode(audio=0): |
||||||
|
in_src2.push(frame) |
||||||
|
while True: |
||||||
|
try: |
||||||
|
filtered_frame = pad.pull() |
||||||
|
output_container.mux(output_audio_stream.encode(filtered_frame)) |
||||||
|
except: |
||||||
|
break |
||||||
|
|
||||||
|
for packet in output_audio_stream.encode(): |
||||||
|
output_container.mux(packet) |
||||||
|
|
||||||
|
input_container.close() |
||||||
|
input_container2.close() |
||||||
|
output_container.close() |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
Loading…
Reference in new issue