I'm trying to take a pile of screenshot PNGs, and the timestamp of each screenshot, and create a video with ffmpeg that recreates the timing of the screenshots.
According to the ffmpeg help, -vsync 0 seems to be what I need,
-vsync parameter
0, passthrough Each frame is passed with its timestamp from the
demuxer to the muxer.
Does anyone know how to pass this timestamp information into ffmpeg? Presently each screenshot has the recording time in milliseconds as the filename.
The below example doesn't accept any timing information that I can tell, so I'm looking for the proper format to pipe to the command.
ffmpeg -vsync 0 -pattern_type glob -i '*.png' -c:v libx264 output.mp4
Script: get time from filename, minus previous filetime = duration of temp video, then concat videos
#!/bin/bash
LST=($(ls -1tr Screenshot*.png))
TOT=${#LST[*]}
f="${LST[0]}"
#Screenshot_20201115_135335.png
FNM="${f%.*}"
SEC="${FNM:24:2}"
MIN="${FNM:22:2}"
HOU="${FNM:20:2}"
echo $f $HOU $MIN $SEC
BEG=$(echo "$HOU * 3600 + $MIN * 60 + $SEC" | bc -l)
echo $f $BEG
INP=("-i" "$f")
OUT="${f%.*}.mkv"
TXT=list.txt
echo "#png to mkv" > $TXT
for (( i=1; i<=$(( $TOT -1 )); i++ )); do
f="${LST[$i]}"
FNM="${f%.*}"
SEC="${FNM:24:2}"
MIN="${FNM:22:2}"
HOU="${FNM:20:2}"
TIM=$(echo "$HOU * 3600 + $MIN * 60 + $SEC" | bc -l)
DUR=$(echo "$TIM - $BEG" | bc -l)
echo $f $TIM $DUR
ffmpeg -y -hide_banner -loop 1 "${INP[#]}" -t $DUR "/tmp/${OUT}"
echo "file '/tmp/${OUT}'" >> $TXT
BEG=$TIM
INP=("-i" "$f")
OUT="${f%.*}.mkv"
done
ffmpeg -y -hide_banner -loop 1 "${INP[#]}" -t 5 "/tmp/${OUT}"
echo "file '/tmp/${OUT}'" >> $TXT
cat "$TXT"
ffmpeg -hide_banner -f concat -safe 0 -i "$TXT" -c:v h264_nvenc -cq 20 -y /tmp/output.mkv
ffplay /tmp/output.mkv
Related
This question already has an answer here:
dotnet ef scaffold Unrecognized option '-t firstTable -t secondTable' - pass arguments stored in a string
(1 answer)
Closed 6 months ago.
Per the suggestion from mklement0 I have shortened the output here to just the relevant code and error. Additionally, as he pointed out, I have changed how I am constructing the arguments (now passing as an array).
Additionally, the comment from kesh, I removed the "-filter_complex" and changed to just several "-map" 's.
$TEMPDIR = "E:\MediaConversions\BitLadder"
$FOLDER = 'White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO'
$OUTPUTDIR = $TEMPDIR + '\' + $FOLDER
# Mux the 8 Bitrate Ladder steps into a single file, with a common audio stream
$STEPS = #(Get-ChildItem -Path $OUTPUTDIR -Name)
$INPUT_FILES = #()
$MAP = #()
$COUNT = 0
ForEach ($STEP in $STEPS){
$INPUT_FILES += ('-i', "$STEP")
$MAP += ('-map ' + "$COUNT" + ':v', '-map ' + "$COUNT" + ':a')
$COUNT++
}
$OPTIONS = ('-' + "$INPUT_FILES", "$MAP")
#$OPTIONS
D:\Applications\ffmpeg\bin\ffmpeg.exe "$OPTIONS" -f matroska "E:\MediaConversions\White.Boy.Rick.2018_MultiStreamTest_AAC.H264.mkv"
But Sadly, I still get the same frustrating error:
Unrecognized option '-i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP1.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP2.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP3.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP4.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP5.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP6.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP7.mp4 -i White.Boy.Rick.2018.1080p.WEB-DL.H264.AC3-EVO_STEP8.mp4 -map 0:v -map 0:a -map 1:v -map 1:a -map 2:v -map 2:a -map 3:v -map 3:a -map 4:v -map 4:a -map 5:v -map 5:a -map 6:v
-map 6:a -map 7:v -map 7:a'.
Error splitting the argument list: Option not found
You don't need -complex_filter just to map input streams to output file. You just need to use -map as many times as you have streams:
... -map 0:v -map 1:v ... -map 0:a -map 1:a ...
I am using FFPROBE to get some file durations in PowerShell.
For my video it gets the frame count properly but for my audio files it returns a different frame count.
This is my code:
$audioId = "$id.m4a"
$videoId = "$id.mp4"
$duration1 = ffprobe -i $videoId -show_frames 2>&1 | grep -c media_type=video
$duration2 = ffprobe -i $audioId -show_frames 2>&1 | grep -c media_type=audio
echo $duration1
echo $duration2
For video it returns a proper output, but for audio it returns a wrong result.
Any suggestions?
Thank you
I have got a list of the top 20 files/folders that are taking the most amount of room on my hard drive. I would like to separate them into size path/to/file. Below is what I have done so far.
I am using: var=$(du -a -g /folder/ | sort -n -r | head -n 20). It returns the following:
120 /path/to/file
115 /path/to/another/file
110 /file/path/
etc.
I have tried the following code to split it up into single lines.
for i in $(echo $var | sed "s/\n/ /g")
do
echo "$i"
done
The result I would like is as follows:
120 /path/to/file,
115 /path/to/another/file,
110 /file/path/,
etc.
This however is the result I am getting:
120,
/path/to/file,
115,
/path/to/another/file,
110,
/file/path/,
etc.
I think awk will be easier, can be combined with a pipe to the original command:
du -a -g /folder/ | sort -n -r | head -n 20 | awk '{ print $1, $2 "," }'
If you can not create a single pipe, and have to use $var
echo "$var" | awk '{ print $1, $2 "," }'
In terminal we can use
top -l 2 -F -R | awk '/CPU usage/ && NR>5 {printf "%d", $7+0}'
to get the value of cpu usage how can i get the value as an integer in apple script?
i tried this
set usedSpace to (do shell script "top -l 2 -F -R | awk '/CPU usage/ && NR>5 {printf "%d", $7+0}'") as integer
and gor the error
Expected “,” but found unknown token
then tried like this
set usedSpace to (do shell script "top -l 2 -F -R | awk '/CPU usage/ && NR>5 '; printf $5}") as integer
and got an error like this
error "Can’t make \"CPU usage: 6.40% user, 5.41% sys, 88.17% idle }\"
into type integer." number -1700 from "CPU usage: 6.40% user, 5.41%
sys, 88.17% idle }" to integer
can anybody help me solve this?
Thanks in advance
Try:
set usedSpace to (do shell script "top -l 2 -F -R | awk '/CPU usage/ && NR>5 {printf \"%d\", $7+0}'") as integer
or
set usedSpace to (do shell script "top -l 2 -F -R | awk '/CPU usage/ && NR>5 '; printf $5}") as text
I just want to swap the first 64 characters of a file with the last 64 characters of the same binary file.
How can I do that?
I'm not sure if this can be done reliably with sed or awk. I can imagine a solution that would work on a specific file, or with certain odd conditions like where newlines might appear.
This is fairly easy to do in C. And if not restricted to sed or awk, it can be done with shell commands, too:
n=64
f=/tmp/test
eval $(stat -s $f)
e=$(($st_size - $n))
dd bs=1 count=$n if=$f iseek=$e of=/tmp/last64
dd bs=$n count=1 if=$f of=/tmp/first64
dd bs=1 count=$n if=/tmp/first64 seek=$e of=$f conv=notrunc
dd bs=$n count=1 if=/tmp/last64 of=$f conv=notrunc
Using xxd:
n=64
file=data
tmp=tmp
len=$(wc -c < "$file")
offset=$((len - n))
len=$((offset - n))
xxd -s -$n "$file" | xxd -r -s -$offset > "$tmp"
xxd -s $n -l $len "$file" | xxd -r >> "$tmp"
xxd -l $n "$file" | xxd -r >> "$tmp"
mv "$tmp" "$file"
Edit:
Another approach would be to use xxd and sed:
n=64; hd=$((n * 2))
file=data
tmp=tmp
xxd -c $n -p "$file" |
sed "1{x;d};:a;N;s/\n//;\${s/\(.*\)\(.\{$hd\}\)\$/\2\1/;G};ba" |
xxd -r -p > "$tmp"
mv "$tmp" "$file"
Instead of six calls to xxd, it's two to xxd and one to sed (and fewer file reads and writes, too).
Explanation of the sed command:
1{x;d} - Save the first line of hex digits in hold space. The length of the line is set to the number of bytes to swap using the -c option of xxd.
:a - Label "a"
N - Append the next line.
s/\n// - Remove the embedded newline
\${ - If it's the last line of input:
s/\(.*\)\(.\{$hd\}\)\$/\2\1/ - Swap the last $hd bytes to the beginning
G - Append the first $n bytes from hold space onto the end. Since it's the last line, the script ends.
} - end if
ba - Branch to label "a".
Additionally, sed could do some manipulation of the data.