cliping a webm file using moviepy and ffmpeg parameters - python

Using moviepy, I am trying to trim a section of a webm file like this:
my_file.write_videofile(name, codec = 'libvpx')
Of course, I have already defined the beginning and end of the clip, etc. The code is returning the segment I want, however, I am noticed a decrease in the quality of the file.
I am not resizing or constraiing the file size anywhere, so I don't understand why the clip has an inferior quality compared to the original.
There are some parameters that I could play with, which I suspect are set as defaults in moviepy to speed of video manipulation, but the documentation of moviepy does not say anything about them:
ffmpeg_params :
Any additional ffmpeg parameters you would like to pass, as a list of
terms, like [‘-option1’, ‘value1’, ‘-option2’, ‘value2’]
Anybody outhere is familiar with the right parameters to keep the quality of the original file? As an alternative, is anybody is familiar with any other library to trim webm files?
Below are two pics showing the difference in quality. The first one is a frame of the trimmed file, the second one is approximately the same frame, for the original file.
Thank you

The parameter you are looking for is "bitrate" (for some reason I omitted it in the docs, it will be fixed for the next versions). If you don't provide it, ffmpeg has a default value which is indeed very low.
myclip.write_videofile("test_1.webm", bitrate="50k") # low quality.
myclip.write_videofile("test_2.webm", bitrate="50000k") # high quality.
You can also tune the bitrate of the audio with `audio_bitrate='50k' by the way. The bitrate gives ffmpeg an upper bound on what the bitrate can be, but most of the time when you provide "50000k" the actual bitrate will be below "50000k". 50000k provides nice-quality videos, but keep in mind that webm is still a lossy format.

Related

How to improve the quality of function ‘image.save()’?

I saved the image to the clipboard, and when I read the image information from the clipboard and saved it locally, the image quality changed. How can I save it to maintain the original high quality?
from PIL import ImageGrab
im = ImageGrab.grabclipboard()
im.save('somefile.png','PNG')
I tried adding the parameter 'quality=95' in im.save(), but it didn't work. The original image quality is 131K, and the saved image is 112K.
The size of the file is not directly related to the quality of the image. It also depends on how efficiently the encoder does its job. As it is PNG, the process is lossless, so you don't need to worry - the quality is retained.
Note that the quality parameter has a different meaning when saving JPEG files versus PNG files:
With JPEG files, if you specify a lower quality you are effectively allowing the encoder to discard more information and give up image quality in return for a smaller file size.
With PNG, your encoding and decoding are lossless. The quality is a hint to the decoder as to how much time to spend compressing the file (always losslessly) and about the types of filtering/encoding that may suit best. It is more akin to the parameter to gzip like --best or --fast.
Further information about PNG format is here on Wikipedia.
Without analysing the content of the two images it is impossible to say why the sizes differ - there could be many reasons:
One encoder may have noticed that the image contains fewer than 256 colours and so has decided to use a palette whereas the other may not have done. That could make the images size differ by a factor of 3 times, yet the quality would be identical.
One encoder may use a larger buffer and spend longer looking for repeating patterns in the image. For a simplistic example, imagine the image was 32,000 pixels wide and each line was the same as the one above. If one encoder uses an 8kB buffer, it can never spot that the image just repeats over and over down the page so it has to encode every single line in full, whereas an encoder with a 64kB buffer might just be able to use 1 byte per line and use the PNG filtering to say "same as line above".
One encoder might decide, on grounds of simplicity of code or for lack of code space, to always encode the data in a 16-bit version even if it could use just 8 bits.
One encoder might decide it is always going to store an alpha layer even if it is opaque because that may make the code/data cleaner simpler.
One encoder may always elect to do no filtering, whilst the other has the code required to do sub, up, average or Paeth filtering.
One encoder may not have enough memory to hold the entire image, so it may have to use a simplistic approach to be assured that it can handle whatever turns up later in the image stream.
I just made these examples up - don't take them was gospel - I am just trying to illustrate some possibilities.
To reproduce an exact copy of file from a clipboard, the only way is if the clipboard contains a byte-for-byte copy of the original. This does not happen when the content comes from the "Copy" function in a program.
In theory a program could be created to do that by setting a blob-type object with a copy of the original file, but that would be highly inefficient and defeat the purpose of the clipboard.
Some points:
- When you copy into the clipboard using the file manager, the clipboard will have a reference to the original file (not the entire file which can potentially be much larger than ram)
- Most programs will set the clipboard contents to some "useful version" of the displayed or selected data. This is very much subject to interpretation by the creator of the program.
- Parsing the clipboard content when reading an image is again subject to the whims of the library used to process the data and pack it back into an image format.
Generally if you want to copy a file exactly you will be better off just copying the original file.
Having said that: Evaluate the purpose of the copy-paste process and decide whether the data you get from the clipboard is "good enough" for the intended purpose. This obviously depends on what you want to use it for.

ImageMagick: scale PNG image with a maximum file-size

How would you scale/optimize/minimally output a PNG image so that it just falls below a certain maximum file size? (The input sources are various - PDF, JPEG, GIF, TIFF...)
I've looked in many places but can't find an answer to this question.
In ImageMagick a JPEG output can do this with extent (see e.g. ImageMagick: scale JPEG image with a maximum file-size), but there doesn't seem to be an equivalent for other file formats e.g. PNG.
I could use Wand or PIL in a loop (preference for python) until the filesize is below a certain value, but for 1000s of images this will have a large I/O overhead unless there's a way to predict/estimate the filesize without writing it out first. Perhaps this is the only option.
I could also wrap the various (macOS) command-line tools in python.
Additionally, I only want to do any compression at all where it's absolutely necessary (the source is mainly text), which leaves a choice of compression algorithms.
Thanks for all help.
PS Other relevant questions:
Scale image according a maximum file size
Compress a PNG image with ImageMagick
python set maximum file size when converting (pdf) to jpeg using e.g. Wand
Edit: https://stackoverflow.com/a/40588202/1021819 is quite close too - though the exact code there already (inevitably?) makes some choices about how to go about reducing the file size (resize in that case). Perhaps there is no generalized way to do this without a multi-dimensional search.
Also, since the input files are PDFs, can this even be done with PIL? The first choice is about rasterization, for which I have been using Wand.
https://stackoverflow.com/a/34618887/1021819 is also useful, in that it uses Wand, so putting that operation within the binary-chop loop seems to be a way forward.
With PNG there is no tradeoff of compression method and visual appearance because PNG is lossless. Just go for the smallest possible file, using
my "pngcrush" application, "optipng", "zopflipng" or the like.
If you need a smaller file than any of those can produce, try reducing the number of colors to 255 or fewer, which will allow the PNG codec to produce an indexed-color PNG (color-type 3) which is around 1/3 of the filesize of an RGB PNG. You can use ImageMagick's "-colors 255" option to do this. However, I recommend the "pngquant" application for this; it does a better job than IM does in most cases.

matplotlib animation movie: quality of movie decreasing with time

I am trying to create a movie with the animation.FuncAnimation function in matplotlib. The movie looks fine interactively, but when I save it with the command
anim2.save('somefilm.mp4',codec='mpeg4', fps=15)
It starts out fine, but then becomes blurry (both using QuickTime and vlc, so I figured it's the movie, not the player).
I've played around with blitting, since I thought it was maybe the fact that the canvas wasn't redrawn, but to no avail. Increasing the bitrate also doesn't help.
Setting dpi=500 does improve the quality of the movie somewhat, though then it gets stuck repeatedly, which makes it difficult to watch.
I was just wondering whether this is the best one can do, or am I missing something?
In order to dig into this problem it is important to understand that video files are usually compressed with a highly lossy compression whereas the interactive display is not compressed. The usual movie compressions are often extremely bad with graphs, and it is a matter of compression parameters.
There are four things you can do:
set the image resolution (by dpi), but this may actually make the output visually poorer, as the problem is usually not in the lacking pixels
set the image bitrate (by bitrate); the higher your bitrate, the better your movie will be - one possibility is to set bitrate=-1 and let matplotlib choose the best bitrate
change the codec (e.g., to codec="libx264")
give extra arguments to the codec (e.g., extra_args=['-pix_fmt', 'yuv420p'])
Unfortunately, these options really depend on the video codec, which is a third-party program (usually ffmpeg), the intended use of your video, and your platform. I would start by adding the kwarg bitrate=-1 to see if it improves things.
If you cannot make it work, please add a full (but as simple as possible) example of how to create a bad file. Then it is easier to debug!
I was having the same problem while animating ~3500 frames of some subsurface water current vectors over a basemap and finally fixed the problem. I had been trying to set the bitrate in the anim.save declaration but was still getting the same blurriness later in the animation. What I had to do was set the bitrate when defining the writer:
plt.rcParams['animation.ffmpeg_path']='C:/ffmpeg/bin/ffmpeg.exe'
writer=animation.FFMpegWriter(bitrate=500)
anim.save('T:/baysestuaries/USERS/TSansom/Tiltmeters/testdeployment/tilt2.mp4',
writer=writer,fps=8)
If I set the bitrate to anything less than 500 the animation would still get blurry. bitrate=-1 and codec='libx264' did nothing for me. Hope this helps!

Reading a .JPG Image and Saving it without file size change

I want to write a python code that reads a .jpg picture, alter some of its RBG components and save it again, without changing the picture size.
I tried to load the picture using OpenCV and PyGame, however, when I tried a simple Load/Save code, using three different functions, the resulting images is greater in size than the initial image. This is the code I used.
>>> import cv, pygame # Importing OpenCV & PyGame libraries.
>>> image_opencv = cv.LoadImage('lena.jpg')
>>> image_opencv_matrix = cv.LoadImageM('lena.jpg')
>>> image_pygame = pygame.image.load('lena.jpg')
>>> cv.SaveImage('lena_opencv.jpg', image_opencv)
>>> cv.SaveImage('lena_opencv_matrix.jpg', image_opencv_matrix)
>>> pygame.image.save(image_pygame, 'lena_pygame.jpg')
The original size was 48.3K, and the resulting are 75.5K, 75.5K, 49.9K.
So, I'm not sure I'm missing something that makes the picture original size changes, although I only made a Load/Save, or not?
And is there a better library to use rather than OpenCV or PyGame ?!
JPEG is a lossy image format. When you open and save one, you’re encoding the entire image again. You can adjust the quality settings to approximate the original file size, but you’re going to lose some image quality regardless. There’s no general way to know what the original quality setting was, but if the file size is important, you could guess until you get it close.
The size of a JPEG output depends on 3 things:
The dimensions of the original image. In your case these are the same for all 3 examples.
The color complexity within the image. An image with a lot of detail will be bigger than one that is totally blank.
The quality setting used in the encoder. In your case you used the defaults, which appear to be higher for OpenCV vs. PyGame. A better quality setting will generate a file that's closer to the original (less lossy) but larger.
Because of the lossy nature of JPEG some of this is slightly unpredictable. You can save an image with a particular quality setting, open that new image and save it again at the exact same quality setting, and it will probably be slightly different in size because of the changes introduced when you saved it the first time.

Generate volume curve from mp3

I'm trying to build something in python that can analyze an uploaded mp3 and generate the necessary data to build a waveform graphic. Everything I've found is much more complex than I need. Ultimately, I'm trying to build something like you'd see on SoundCloud.
I've been looking into numpy and fft's, but it all seem more complicated than I need. What's the best approach to this? I'll build the actual graphic using canvas, so don't worry about that part of it, I just need the data to plot.
An MP3 file is an encoded version of a waveform. Before you can work with the waveform, you must first decode the MP3 data into a PCM waveform. Once you have PCM data, each sample represents the waveform's amplitude at the point in time. If we assume an MP3 decoder outputs signed, 16-bit values, your amplitudes will range from -16384 to +16383. If you normalize the samples by dividing each by 16384, the waveform samples will then range between +/- 1.0.
The issue really is one of MP3 decoding to PCM. As far as I know, there is no native python decoder. You can, however, use LAME, called from python as a subprocess or, with a bit more work, interface the LAME library directly to Python with something like SWIG. Not a trivial task.
Plotting this data then becomes an exercise for the reader.
I suggest you using Pygame if you don't want to deal with the inner workings of the mp3 file format.
Pygame is a multimedia library which can open common audio file formats - including .mp3 and .ogg as "Sound" objects - if you have Numpy instaled underneath, you can browse the uncompressed (and therefore, post fft transforms) sound, using the pygame.sndarray.array call - which returns a numpy array object with the sound samples.
I've found a little trick - be shure to call pygame.mixer.init with the same parameters (for frequency, bit sample size and n.of channels) as your .mp3 file has, or the call to sndarray.array may raise an Exception.
Check the documentation at http://www.pygame.org/docs/

Categories