AviSynth script with subtitles errors - ffmpeg

Win7
FFmpeg version: 20170223-dcd3418 win32 shared
AVISynth version: 2.6
Calling ffmpeg in a Visual Studio 2015 C# Forms Application and using process.StartInfo.Arguments to pass arguments and read an avs script. Works fine.
The avs script:
LoadPlugin("C:\Program Files (x86)\AviSynth 2.5\plugins\VSFilter.dll")
a=ImageSource("01.png").trim(1,24)
b=ImageSource("02.png").trim(1,36)
c=ImageSource("03.png").trim(1,40)
d=ImageSource("04.png").trim(1,72)
e=ImageSource("05.png").trim(1,36)
f=ImageSource("06.png").trim(1,40)
video = a + b + c + d + e + f
return video
I'd like to add subtitles using the avs script but it is not working. Adding the subtitle argument immediately before the "return video" argument results in:
subtitle("day 111", align=2, first_frame=0, halo_color=$00FF00FF, text_color=$0000FF00, size=36, last_frame=100)
Result error: [avisynth # 003cdf20] Script error: Invalid arguments to function "subtitle"
Using video.subtitle results in:
video.subtitle("day 111", align=2, first_frame=0, halo_color=$00FF00FF, text_color=$0000FF00, size=36, last_frame=100)
No error, script completes but no subtitle on output video.
Using subtitle(clip) results in:
subtitle(video, "day 111", align=2, first_frame=0, halo_color=$00FF00FF, text_color=$0000FF00, size=36, last_frame=100)
The script exits abnormally but there is no error message.
Any guidance would be greatly appreciated. Please let me know if I can clarify anything.

Thanks, that worked.
LoadPlugin("C:\Program Files (x86)\AviSynth 2.5\plugins\VSFilter.dll")
a=ImageSource("01.png").trim(1,24)
b=ImageSource("02.png").trim(1,36)
c=ImageSource("03.png").trim(1,40)
d=ImageSource("04.png").trim(1,72)
e=ImageSource("05.png").trim(1,36)
f=ImageSource("06.png").trim(1,40)
subtitle(a + b + c + d + e + f, "day 111", align=9, first_frame=0, halo_color=$00FF00FF, text_color=$0000FF00, size=36, last_frame=100)

Related

Using PyAV to encode mono audio to file, params match docs, but still causes Errno 22

While trying to use PyAV to encode live mono audio from a microphone to a compressed audio stream (using mp2 or flac as encoder), the program kept raising an exception ValueError: [Errno 22] Invalid argument.
To remove the live microphone source as a cause of the problem, and to make the problematic code easier for others to run/test, I have removed the mic source and now just generate a pure tone as a sequence of input buffers.
All attempts to figure out the missing or mismatched or incorrect argument have just resulted in seeing documentation and examples that are the same as my code.
I would like to know from someone who has used PyAV successfully for mono audio what the correct method and parameters are for encoding mono frames into the mono stream.
The package used is av 10.0.0 installed with
pip3 install av --no-binary av
so it uses my package-manager provided ffmpeg library, which is version 4.2.7.
The problematic python code is:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Recreating an error 22 when encoding sound with PyAV.
Created on Sun Feb 19 08:10:29 2023
#author: andrewm
"""
import typing
import sys
import math
import fractions
import av
from av import AudioFrame
""" Ensure some PyAudio constants are still defined without changing
the PyAudio recording callback function and without depending
on PyAudio simply for reproducing the PyAV bug [Errno 22] thrown in
File "av/filter/context.pyx", line 89, in av.filter.context.FilterContext.push
"""
class PA_Stub():
paContinue = True
paComplete= False
pyaudio = PA_Stub()
"""Generate pure tone at given frequency with amplitude 0...1.0 at
sampling frewuency fs and beginning at phase offset 'phase'.
Returns the new phase after the sinusoid has cycled over the
sampling window length.
"""
def generate_tone(
freq:int, phase:float, amp:float, fs, samp_fmt, buffer:bytearray
) -> float:
assert samp_fmt == "s16", "Only s16 supported atm"
samp_size_bytes = 2
n_samples = int(len(buffer)/samp_size_bytes)
window = [int(0) for i in range(n_samples)]
theta = phase
phase_inc = 2*math.pi * freq / fs
for i in range(n_samples):
v = amp * math.sin(theta)
theta += phase_inc
s = int((2**15-1)*v)
window[i] = s
for sample_i in range(len(window)):
byte_i = sample_i * samp_size_bytes
enc = window[sample_i].to_bytes(
2, byteorder=sys.byteorder, signed=True
)
buffer[byte_i] = enc[0]
buffer[byte_i+1] = enc[1]
return theta
channels = 1
fs = 44100 # Record at 44100 samples per second
fft_size_samps = 256
chunk_samps = fft_size_samps * 10 # Record in chunks that are multiples of fft windows.
# print(f"fft_size_samps={fft_size_samps}\nchunk_samps={chunk_samps}")
seconds = 3.0
out_filename = "testoutput.wav"
# Store data in chunks for 3 seconds
sample_limit = int(fs * seconds)
sample_len = 0
frames = [] # Initialize array to store frames
ffmpeg_codec_name = 'mp2' # flac, mp3, or libvorbis make same error.
sample_size_bytes = 2
buffer = bytearray(int(chunk_samps*sample_size_bytes))
chunkperiod = chunk_samps / fs
total_chunks = int(math.ceil(seconds / chunkperiod))
phase = 0.0
### uncomment if you want to see the synthetic data being used as a mic input.
# with open("test.raw","wb") as raw_out:
# for ci in range(total_chunks):
# phase = generate_tone(2600, phase, 0.8, fs, "s16", buffer)
# raw_out.write(buffer)
# print("finished gen test")
# sys.exit(0)
# #----
# Using mp2 or mkv as the container format gets the same error.
with av.open(out_filename+'.mp2', "w", format="mp2") as output_con:
output_con.metadata["title"] = "My title"
output_con.metadata["key"] = "value"
channel_layout = "mono"
sample_fmt = "s16p"
ostream = output_con.add_stream(ffmpeg_codec_name, fs, layout=channel_layout)
assert ostream is not None, "No stream!"
cctx = ostream.codec_context
cctx.sample_rate = fs
cctx.time_base = fractions.Fraction(numerator=1,denominator=fs)
cctx.format = sample_fmt
cctx.channels = channels
cctx.layout = channel_layout
print(cctx, f"layout#{cctx.channel_layout}")
# Define PyAudio-style callback for recording plus PyAV transcoding.
def rec_callback(in_data, frame_count, time_info, status):
global sample_len
global ostream
frames.append(in_data)
nsamples = int(len(in_data) / (channels*sample_size_bytes))
frame = AudioFrame(format=sample_fmt, layout=channel_layout, samples=nsamples)
frame.sample_rate = fs
frame.time_base = fractions.Fraction(numerator=1,denominator=fs)
frame.pts = sample_len
frame.planes[0].update(in_data)
print(frame, len(in_data))
for out_packet in ostream.encode(frame):
output_con.mux(out_packet)
for out_packet in ostream.encode(None):
output_con.mux(out_packet)
sample_len += nsamples
retflag = pyaudio.paContinue if sample_len<sample_limit else pyaudio.paComplete
return (in_data, retflag)
print('Beginning')
### some e.g. PyAudio code which starts the recording process normally.
# istream = p.open(
# format=sample_format,
# channels=channels,
# rate=fs,
# frames_per_buffer=chunk_samps,
# input=True,
# stream_callback=rec_callback
# )
# print(istream)
# Normally at this point you just sleep the main thread while
# PyAudio calls back with mic data, but here it is all generated.
for ci in range(total_chunks):
phase = generate_tone(2600, phase, 0.8, fs, "s16", buffer)
ret_data, ret_flag = rec_callback(buffer, ci, {}, 1)
print('.', end='')
print(" closing.")
# Stop and close the istream
# istream.stop_stream()
# istream.close()
If you uncomment the RAW output part you will find the generated data can be imported as PCM s16 Mono 44100Hz into Audacity and plays the expected tone, so the generated audio data does not seem to be the problem.
The normal program console output up until the exception is:
<av.AudioCodecContext audio/mp2 at 0x7f8e38202cf0> layout#4
Beginning
<av.AudioFrame 0, pts=0, 2560 samples at 44100Hz, mono, s16p at 0x7f8e38202eb0> 5120
.<av.AudioFrame 0, pts=2560, 2560 samples at 44100Hz, mono, s16p at 0x7f8e382025f0> 5120
The stack trace is:
Traceback (most recent call last):
File "Dev/multichan_recording/av_encode.py", line 147, in <module>
ret_data, ret_flag = rec_callback(buffer, ci, {}, 1)
File "Dev/multichan_recording/av_encode.py", line 121, in rec_callback
for out_packet in ostream.encode(frame):
File "av/stream.pyx", line 153, in av.stream.Stream.encode
File "av/codec/context.pyx", line 484, in av.codec.context.CodecContext.encode
File "av/audio/codeccontext.pyx", line 42, in av.audio.codeccontext.AudioCodecContext._prepare_frames_for_encode
File "av/audio/resampler.pyx", line 101, in av.audio.resampler.AudioResampler.resample
File "av/filter/graph.pyx", line 211, in av.filter.graph.Graph.push
File "av/filter/context.pyx", line 89, in av.filter.context.FilterContext.push
File "av/error.pyx", line 336, in av.error.err_check
ValueError: [Errno 22] Invalid argument
edit: It's interesting that the error happens on the 2nd AudioFrame, as apparently the first one was encoded okay, because they are given the same attribute values aside from the Presentation Time Stamp (pts), but leaving this out and letting PyAV/ffmpeg generate the PTS by itself does not fix the error, so an incorrect PTS does not seem the cause.
After a brief glance in av/filter/context.pyx the exception must come from a bad return value from res = lib.av_buffersrc_write_frame(self.ptr, frame.ptr)
Trying to dig into av_buffersrc_write_frame from the ffmpeg source it is not clear what could be causing this error. The only obvious one is a mismatch between channel layouts, but my code is setting the layout the same in the Stream and the Frame. That problem had been found by an old question pyav - cannot save stream as mono and their answer (that one parameter required is undocumented) is the only reason the code now has the layout='mono' argument when making the stream.
The program output shows layout #4 is being used, and from https://github.com/FFmpeg/FFmpeg/blob/release/4.2/libavutil/channel_layout.h you can see this is the value for symbol AV_CH_FRONT_CENTER which is the only channel in the MONO layout.
The mismatch is surely some other object property or an undocumented parameter requirement.
How do you encode mono audio to a compressed stream with PyAV?

AttributeError: 'Ghostscript' object has no attribute '_instance'

In my university semester project we are attempting to use ghostscript on some PDF files, however when we try to run our code, we get the error:
AttributeError: 'Ghostscript' object has no attribute '_instance'
We have tried various attempts to fix this, however have not found a solution yet. The only part in which we are using ghostscript is the following code:
ar = ["-sDEVICE=pdfwrite", "-dPDFSETTINGS=/prepress", "-dQUIET", "-dBATCH", "-dNOPAUSE", "-dPDFSETTINGS=/printer", "-sOutputFile=" + os.path.join(filepath, file), os.path.join(filepath, file)]
gs = ghostscript.Ghostscript(*ar)
del gs
We are using Python-3.8 and PyPi Ghostscript 0.7.
Has anyone else encountered this error or does anyone know how to fix it?
Apparently the order in which you pass the arguments is important. So instead of having:
ar = ["-sDEVICE=pdfwrite", "-dPDFSETTINGS=/prepress", "-dQUIET", "-dBATCH", "-dNOPAUSE", "-dPDFSETTINGS=/printer", "-sOutputFile=" + os.path.join(filepath, file), os.path.join(filepath, file)]
We now have:
ar = ["-dQUIET", "-dBATCH", "-dNOPAUSE", "-sDEVICE=pdfwrite", "-dPDFSETTINGS=/prepress", "-dPDFSETTINGS=/printer", "-sOutputFile=" + os.path.join(filepath, file), os.path.join(filepath, file)]
This solved the issue for us.

Internal exaption on play sound in QMediaPlayer

When I try to execute "play" with loop on file that not exist, I got exaption "stack_overflow".
I use Qt 5.15.2 and windows 7
playlist->addMedia(QUrl::fromLocalFile("not_exist"));
playlist->setPlaybackMode(QMediaPlaylist::Loop);
QMediaPlayer *music = new QMediaPlayer();
music->setPlaylist(playlist);
music->play();
Can I catch this exception or maybe I can use another way to run sound in the loop to exclude this problem?
You have to use the error signal of QMediaPlayer:
connect(music, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error),
[music](QMediaPlayer::Error error){
qDebug() << error << music->errorString();
});
Output:
QMediaPlayer::ResourceError "Could not open resource for reading."

How to debug with PureScript?

Issue
Following is a minimal, contrived example:
read :: FilePath -> Aff String
read f = do
log ("File: " <> f) -- (1)
readTextFile UTF8 f -- (2)
I would like to do some debug logging in (1), before a potential error on (2) occurs. Executing following code in Spago REPL works for success cases so far:
$ spago repl
> launchAff_ $ read "test/data/tree/root.txt"
File: test/data/tree/root.txt
unit
Problem: If there is an error with (2) - file is directory here - , (1) seems to be not executed at all:
$ spago repl
> launchAff_ $ read "test/data/tree"
~/purescript-book/exercises/chapter9/.psci_modules/node_modules/Effect.Aff/foreign.js:532
throw util.fromLeft(step);
^
[Error: EISDIR: illegal operation on a directory, read] {
errno: -21,
code: 'EISDIR',
syscall: 'read'
}
The original problem is more complex including several layers of recursions (see E-Book exercise 3), where I need logging to debug above error.
Questions
How can I properly log regardless upcoming errors here?
(Optional) Is there a more sophisticated, well-established debugging alternative - purescript-debugger? A decicated VS Code debug extension/functionality would be the cherry on the cake.
First of all, the symptoms you observe do not mean that the first line doesn't execute. It does always execute, you're just not seeing output from it due to how console works in the PureScript REPL. The output gets swallowed. Not the only problem with REPL, sadly.
You can verify that the first line is always executed by replacing log with throwError and observing that the error always gets thrown. Or, alternatively, you can make the first line modify a mutable cell instead of writing to the console, and then examine the cell's contents.
Finally, this only happens in REPL. If you put that launchAff_ call inside main and run the program, you will always get the console output.
Now to the actual question at hand: how to debug trace.
Logging to console is fine if you can afford it, but there is a more elegant way: Debug.trace.
This function has a hidden effect - i.e. its type says it's pure, but it really produces an effect when called. This little lie lets you use trace in a pure setting and thus debug pure code. No need for Effect! This is ok as long as used for debugging only, but don't put it in production code.
The way it works is that it takes two parameters: the first one gets printed to console and the second one is a function to be called after printing, and the result of the whole thing is whatever that function returns. For example:
calculateSomething :: Int -> Int -> Int
calculateSomething x y =
trace ("x = " <> show x) \_ ->
x + y
main :: Effect Unit
main =
log $ show $ calculateSomething 37 5
> npx spago run
'x = 37'
42
The first parameter can be anything at all, not just a string. This lets you easily print a lot of stuff:
calculateSomething :: Int -> Int -> Int
calculateSomething x y =
trace { x, y } \_ ->
x + y
> npx spago run
{ x: 37, y: 5 }
42
Or, applying this to your code:
read :: FilePath -> Aff String
read f = trace ("File: " <> f) \_ -> do
readTextFile UTF8 f
But here's a subtle detail: this tracing happens as soon as you call read, even if the resulting Aff will never be actually executed. If you need tracing to happen on effectful execution, you'll need to make the trace call part of the action, and be careful not to make it the very first action in the sequence:
read :: FilePath -> Aff String
read f = do
pure unit
trace ("File: " <> f) \_ -> pure unit
readTextFile UTF8 f
It is, of course, a bit inconvenient to do this every time you need to trace in an effectful context, so there is a special function that does it for you - it's called traceM:
read :: FilePath -> Aff String
read f = do
traceM ("File: " <> f)
readTextFile UTF8 f
If you look at its source code, you'll see that it does exactly what I did in the example above.
The sad part is that trace won't help you in REPL when an exception happens, because it's still printing to console, so it'll still get swallowed for the same reasons.
But even when it doesn't get swallowed, the output is a bit garbled, because trace actually outputs in color (to help you make it out among other output), and PureScript REPL has a complicated relationship with color:
> calculateSomething 37 5
←[32m'x = 37'←[39m
42
In addition to Fyodor Soikin's great answer, I found a variant using VS Code debug view.
1.) Make sure to build with sourcemaps:
spago build --purs-args "-g sourcemaps"
2.) Add debug configuration to VS Code launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"runtimeArgs": ["-e", "require('./output/Main/index.js').main()"],
"smartStep": true // skips files without (valid) source map
}
]
}
Replace "./output/Main/index.js" / .main() with the compiled .js file / function to be debugged.
3.) Set break points and step through the .purs file via sourcemap support.

python FTP error when dowloading all files in a list

does someone know why python is not downloading all the files in the list below? The first file downloads and then i get an 'error2' for the second file.
fdnload1 = ['AAA092214.TXT', '092214 REPORT TOTALS.TXT']
try:
# DOWNLOAD FILES
for fdn in fdnload1:
ftrans1 = open(fdn,'wb')
ftp.retrbinary('RETR ' + fdn, ftrans1.write)
print 'Downloading...' + fdn
except:
print 'error2'
results:
Downloading...AAA092214.TXT
error2
when i run the program without actually downloading the files, it iterates through all files:
try:
# DOWNLOAD FILES
for fdn in fdnload1:
print 'Downloading...' + fdn
except:
print 'error2'
results:
Downloading...AAA092214.TXT
Downloading...092214 REPORT TOTALS.TXT
[Finished in 0.3s]
E D I T # 1:
i was able to get all files in fdnload1 to download by creating a separate function to download files, but i am still getting errors, and they are coming from the actual download process (see my results are printing 'error in download1() function'. does anyone know why?
also, i just checked the files that were downloaded and they are empty, so they did not actually download properly...
def download1(fdn):
os.chdir('C:/directory10')
try:
ftrans1 = open(fdn,'wb')
ftp.retrbinary('RETR ' + fdn, ftrans1.write)
print 'file: ' + fdn + 'download complete...'
except:
print 'error in download1() function'
modified the original code to run the download() function:
try:
# DOWNLOAD FILES
for fdn in fdnload1:
print 'Downloading... ' + fdn
download1(fdn)
except:
print 'error2'
results:
Downloading... AAA092214.TXT
error in download1() function
Downloading... 092214 REPORT TOTALS.TXT
error in download1() function
it was user permissions error on the ftp side.
ftplib.error_perm: 550 AASN092214.PCI: Permission denied.
logged in under superuser and i was able to download all files with and without the download1() function...
thanks

Resources