Compare commits
	
		
			3 Commits
		
	
	
		
			master
			...
			setup-arek
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5e15153eef | |||
| 58dd1d5beb | |||
| 068ab054bb | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -2,3 +2,5 @@ | |||||||
| *.mp4 | *.mp4 | ||||||
| out/* | out/* | ||||||
| !out/keepme | !out/keepme | ||||||
|  | *.wav | ||||||
|  | .DS_Store | ||||||
							
								
								
									
										1
									
								
								add-glitch.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | ffmpeg -hwaccel videotoolbox -i glitch.mp4 -i video-with-new-audio.mp4 -i glitch.mp4 -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[vv][aa]" -map "[vv]" -map "[aa]" -c:v libx264 -r 50 -c:a aac -strict experimental -b:a 320k output.mp4 | ||||||
							
								
								
									
										9
									
								
								demux.sh
									
									
									
									
									
								
							
							
						
						| @ -1,9 +0,0 @@ | |||||||
| echo "generating the demuxers..." |  | ||||||
| 
 |  | ||||||
| # generuje ścieżki do złożenia przez ffmpega: |  | ||||||
| ts-node generate-demuxer.ts >out/demuxer.txt |  | ||||||
| 
 |  | ||||||
| # używa demuxer.txt żeby skleić końcowe video z dźwiękiem: |  | ||||||
| echo generowanie całości |  | ||||||
| ffmpeg -y -f concat -safe 0 -i out/demuxer.txt -r $framerate -video_track_timescale $timescale -tune stillimage -pix_fmt yuv420p out/video.mp4 |  | ||||||
| #                   ^ daję safe 0 aby przyjmowało bezwzględne ścieżki |  | ||||||
							
								
								
									
										0
									
								
								find-loudness.ts
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								fix-audio.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | ffmpeg -hwaccel videotoolbox -i out/video.mp4 -i icdw-11-final.wav -c:v copy -c:a aac -b:a 320k -strict experimental video-with-new-audio.mp4 | ||||||
							
								
								
									
										116
									
								
								generate-demuxer.ts
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @ -2,9 +2,7 @@ import findLoudness, { SwapPoint } from "./find-loudness"; | |||||||
| 
 | 
 | ||||||
| const graph_density = 8000; | const graph_density = 8000; | ||||||
| 
 | 
 | ||||||
| const threshold_at_point = parseInt( | const threshold_at_point = 2; | ||||||
|   process.env.demuxer_volume_threshold || "1" |  | ||||||
| ); |  | ||||||
| 
 | 
 | ||||||
| const inertia_s = 0.3; | const inertia_s = 0.3; | ||||||
| const inertia_samples = inertia_s * graph_density; | const inertia_samples = inertia_s * graph_density; | ||||||
| @ -16,65 +14,75 @@ const minutes = (units: number) => Math.floor(s(units) / 60); | |||||||
| const hours = (units: number) => Math.floor(units / graph_density / 60 / 60); | const hours = (units: number) => Math.floor(units / graph_density / 60 / 60); | ||||||
| 
 | 
 | ||||||
| const formatTime = (units: number) => | const formatTime = (units: number) => | ||||||
|   `${hours(units)}:${minutes(units)}:${Math.floor(s(units) % 60)}`; | 	`${hours(units)}:${minutes(units)}:${Math.floor(s(units) % 60)}`; | ||||||
| 
 | 
 | ||||||
| type Mode = { left: boolean; right: boolean }; | type Mode = { left: boolean; right: boolean }; | ||||||
| 
 | 
 | ||||||
| async function run() { | async function run() { | ||||||
|   const [left_breaks, right_breaks] = await Promise.all([ | 	const [left_breaks, right_breaks] = await Promise.all([ | ||||||
|     findLoudness("/tmp/leftraw", threshold_at_point, inertia_samples, "left"), | 		findLoudness( | ||||||
|     findLoudness("/tmp/rightraw", threshold_at_point, inertia_samples, "right"), | 			"/tmp/leftraw", | ||||||
|   ]); | 			threshold_at_point, | ||||||
|  | 			inertia_samples, | ||||||
|  | 			"left" | ||||||
|  | 		), | ||||||
|  | 		findLoudness( | ||||||
|  | 			"/tmp/rightraw", | ||||||
|  | 			threshold_at_point, | ||||||
|  | 			inertia_samples, | ||||||
|  | 			"right" | ||||||
|  | 		), | ||||||
|  | 	]); | ||||||
| 
 | 
 | ||||||
|   const merged = [...left_breaks, ...right_breaks].sort((a, b) => | 	const merged = [...left_breaks, ...right_breaks].sort((a, b) => | ||||||
|     a.position_start < b.position_start | 		a.position_start < b.position_start | ||||||
|       ? -1 | 			? -1 | ||||||
|       : a.position_start > b.position_start | 			: a.position_start > b.position_start | ||||||
|       ? 1 | 				? 1 | ||||||
|       : 0 | 				: 0 | ||||||
|   ); | 	); | ||||||
| 
 | 
 | ||||||
|   // console.log("left breaks:", left_breaks);
 | 	// console.log("left breaks:", left_breaks);
 | ||||||
|   // console.log(`right_breaks`, right_breaks);
 | 	// console.log(`right_breaks`, right_breaks);
 | ||||||
|   // console.log(`merged`, merged);
 | 	// console.log(`merged`, merged);
 | ||||||
| 
 | 
 | ||||||
|   function new_mode(m: Mode, s: SwapPoint): Mode { | 	function new_mode(m: Mode, s: SwapPoint): Mode { | ||||||
|     return { ...m, [s.label]: s.loud }; | 		return { ...m, [s.label]: s.loud }; | ||||||
|   } | 	} | ||||||
| 
 | 
 | ||||||
|   function mode_to_string(mode: Mode) { | 	function mode_to_string(mode: Mode) { | ||||||
|     if (mode.left && mode.right) { | 		if (mode.left && mode.right) { | ||||||
|       return "both"; | 			return "both"; | ||||||
|     } | 		} | ||||||
|     for (const side of ["left", "right"]) { | 		for (const side of ["left", "right"]) { | ||||||
|       if (mode[side as keyof Mode]) { | 			if (mode[side as keyof Mode]) { | ||||||
|         return side; | 				return side; | ||||||
|       } | 			} | ||||||
|     } | 		} | ||||||
|     return "none"; | 		return "none"; | ||||||
|   } | 	} | ||||||
| 
 | 
 | ||||||
|   console.log("file", `${process.cwd()}/pics/none.png`); | 	console.log("file", `${process.cwd()}/pics/none.png`); | ||||||
|   let last_point = 0; | 	let last_point = 0; | ||||||
|   let mode: Mode = { left: false, right: false }; | 	let mode: Mode = { left: false, right: false }; | ||||||
|   let last_file; | 	let last_file; | ||||||
|   let total = 0; | 	let total = 0; | ||||||
|   for (let i = 2; i < merged.length; i++) { | 	for (let i = 2; i < merged.length; i++) { | ||||||
|     const point = merged[i]; | 		const point = merged[i]; | ||||||
|     mode = new_mode(mode, point); | 		mode = new_mode(mode, point); | ||||||
|     const file = `${process.cwd()}/pics/${mode_to_string(mode)}.png`; | 		const file = `${process.cwd()}/pics/${mode_to_string(mode)}.png`; | ||||||
|     const duration = (point.position_start - last_point) / graph_density; | 		const duration = (point.position_start - last_point) / graph_density; | ||||||
|     console.log( | 		console.log( | ||||||
|       "duration", | 			"duration", | ||||||
|       (point.position_start - last_point) / graph_density | 			(point.position_start - last_point) / graph_density | ||||||
|     ); | 		); | ||||||
|     console.log("file", file); | 		console.log("file", file); | ||||||
|     last_point = point.position_start; | 		last_point = point.position_start; | ||||||
|     last_file = file; | 		last_file = file; | ||||||
|     total += duration * graph_density; | 		total += duration * graph_density; | ||||||
|   } | 	} | ||||||
|   console.log("duration", merged[merged.length - 1].duration / graph_density); | 	console.log("duration", merged[merged.length - 1].duration / graph_density); | ||||||
|   console.log("file", last_file); | 	console.log("file", last_file); | ||||||
|   console.error(total, formatTime(total)); | 	console.error(total, formatTime(total)); | ||||||
| } | } | ||||||
| run(); | run(); | ||||||
|  | |||||||
							
								
								
									
										49
									
								
								generate.sh
									
									
									
									
									
								
							
							
						
						| @ -6,18 +6,43 @@ | |||||||
| #  W katalogu z tym skryptem musisz mieć katalog "pics", w którym są pliki "left.png", "right.png", "none.png" i "both.png" | #  W katalogu z tym skryptem musisz mieć katalog "pics", w którym są pliki "left.png", "right.png", "none.png" i "both.png" | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| export input=~/Downloads/icdw5/icdw5-stereo.wav                  # tutaj dajemy ścieżkę do pliku mp3 z Arkiem w jednym kanale i Kubą w drugim | framerate=60 | ||||||
| export input_mono=~/Downloads/icdw5/icdw5-stereo.wav             # tutaj dajemy ścieżkę do pliku mp3 z Arkiem w jednym kanale i Kubą w drugim | timescale=25000 | ||||||
| export intro=~/projects/midline/podcast-visualizer/out/intro.mp4 # glitch | 
 | ||||||
| export outro=~/projects/midline/podcast-visualizer/out/intro.mp4 # to samo na końcu, co na początku | aresample=8000   # to bez zmian | ||||||
| export final_output=~/Downloads/icdw5-viz.mp4 | 
 | ||||||
| export framerate=25 | # echo dzielimy mp3 na dwa osobne wav | ||||||
| export timescale=25000 | # ffmpeg -i $input -map_channel 0.0.0 /tmp/left.wav -map_channel 0.0.1 /tmp/right.wav | ||||||
| export demuxer_volume_threshold=15 #od 0 do 128 | 
 | ||||||
|  | 
 | ||||||
|  | ffmpeg -i ./left.wav -ac 1 -filter:a aresample=$aresample -map 0:a -c:a pcm_u8 -f data -  > /tmp/leftraw & | ||||||
|  | ffmpeg -i ./right.wav -ac 1 -filter:a aresample=$aresample -map 0:a -c:a pcm_u8 -f data -  > /tmp/rightraw & | ||||||
|  | 
 | ||||||
|  | # czekamy aż obydwa wątki się zakończą | ||||||
|  | wait; | ||||||
|  | 
 | ||||||
|  | echo "generating the demuxers..."; | ||||||
|  | 
 | ||||||
|  | # generuje ścieżki do złożenia przez ffmpega: | ||||||
|  | 
 | ||||||
|  | ts-node generate-demuxer.ts > out/demuxer.txt | ||||||
| 
 | 
 | ||||||
| aresample=8000 # to bez zmian |  | ||||||
| mkdir -p out | mkdir -p out | ||||||
| 
 | 
 | ||||||
| source ./split.sh | # używa demuxer.txt żeby skleić końcowe video z dźwiękiem: | ||||||
| source ./demux.sh | echo generowanie całości | ||||||
| source ./merge.sh | # ffmpeg -y -f concat -safe 0 -i out/demuxer.txt -r $framerate -video_track_timescale $timescale -tune stillimage -fps_mode vfr -pix_fmt yuv420p out/video.mp4 | ||||||
|  | 
 | ||||||
|  | # linux | ||||||
|  | # ffmpeg -y -f concat -safe 0 -hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device /dev/dri/renderD128 -i out/demuxer.txt -r $framerate -video_track_timescale $timescale -tune stillimage -pix_fmt yuv420p out/video.mp4 | ||||||
|  | 
 | ||||||
|  | # macos mod | ||||||
|  | ffmpeg -y -f concat -safe 0 -hwaccel videotoolbox -i out/demuxer.txt -r $framerate -video_track_timescale $timescale -tune stillimage -pix_fmt yuv420p out/video.mp4 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #                   ^ daję safe 0 aby przyjmowało bezwzględne ścieżki | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # echo łączenie video z dźwiękiem: | ||||||
|  | # ffmpeg  -i out/video.mp4 -i $input -ac 1 -video_track_timescale $timescale -tune stillimage out/video-and-audio.mp4 | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								merge.sh
									
									
									
									
									
								
							
							
						
						| @ -1,44 +0,0 @@ | |||||||
| processed_intro_path=$PWD/out/intro-processed.mp4 |  | ||||||
| processed_outro_path=$PWD/out/outro-processed.mp4 |  | ||||||
| 
 |  | ||||||
| echo łączenie video z dźwiękiem: |  | ||||||
| ffmpeg -y -vaapi_device /dev/dri/renderD128 \ |  | ||||||
| 	-i out/video.mp4 -i $input_mono \ |  | ||||||
| 	-video_track_timescale $timescale \ |  | ||||||
| 	-tune stillimage \ |  | ||||||
| 	-c:a aac \ |  | ||||||
| 	-ac 1 \ |  | ||||||
| 	-strict experimental \ |  | ||||||
| 	-vf 'format=nv12,hwupload' \ |  | ||||||
| 	-c:v h264_vaapi \ |  | ||||||
| 	out/video-and-audio.mp4 |  | ||||||
| 
 |  | ||||||
| echo reencoding intro to enable fast concat... |  | ||||||
| 
 |  | ||||||
| function reencode_for_demux_compatibility() { |  | ||||||
| 	ffmpeg -y -i "$1" \ |  | ||||||
| 		-pix_fmt yuv420p \ |  | ||||||
| 		-r $framerate \ |  | ||||||
| 		-video_track_timescale $timescale \ |  | ||||||
| 		-ac 1 \ |  | ||||||
| 		-b:a 320k \ |  | ||||||
| 		"$2" |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| reencode_for_demux_compatibility "$intro" "$processed_intro_path" |  | ||||||
| 
 |  | ||||||
| if [ "$intro" = "$outro" ]; then |  | ||||||
| 	processed_outro_path="$processed_intro_path" |  | ||||||
| else |  | ||||||
| 	reencode_for_demux_compatibility "$outro" "$processed_outro_path" |  | ||||||
| fi |  | ||||||
| 
 |  | ||||||
| echo "" >out/demuxer-branding.txt |  | ||||||
| echo "file $processed_intro_path" >>out/demuxer-branding.txt |  | ||||||
| echo "file video-and-audio.mp4" >>out/demuxer-branding.txt |  | ||||||
| echo "file $processed_outro_path" >>out/demuxer-branding.txt |  | ||||||
| 
 |  | ||||||
| cat out/demuxer-branding.txt |  | ||||||
| 
 |  | ||||||
| ffmpeg -y -f concat -safe 0 -i out/demuxer-branding.txt -c:v copy -b:a 320k "$final_output" |  | ||||||
							
								
								
									
										0
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								package.json
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								pics/both.png
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 322 KiB | 
							
								
								
									
										
											BIN
										
									
								
								pics/left.png
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 313 KiB | 
							
								
								
									
										
											BIN
										
									
								
								pics/none.png
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| Before Width: | Height: | Size: 287 KiB After Width: | Height: | Size: 301 KiB | 
							
								
								
									
										
											BIN
										
									
								
								pics/right.png
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 313 KiB | 
							
								
								
									
										9
									
								
								split.sh
									
									
									
									
									
								
							
							
						
						| @ -1,9 +0,0 @@ | |||||||
| echo dzielimy mp3 na dwa osobne wav |  | ||||||
| ffmpeg -y -i $input -map_channel 0.0.0 /tmp/left.wav -map_channel 0.0.1 /tmp/right.wav |  | ||||||
| 
 |  | ||||||
| echo na dwóch wątkach generujemy surowe pliki |  | ||||||
| ffmpeg -y -i /tmp/left.wav -ac 1 -filter:a aresample=$aresample -map 0:a -c:a pcm_u8 -f data - >/tmp/leftraw & |  | ||||||
| ffmpeg -y -i /tmp/right.wav -ac 1 -filter:a aresample=$aresample -map 0:a -c:a pcm_u8 -f data - >/tmp/rightraw & |  | ||||||
| 
 |  | ||||||
| # czekamy aż obydwa wątki się zakończą |  | ||||||
| wait |  | ||||||