Losslessly encode png frames to webm with ffmpeg - encoding

I need to convert a directory of frames to webm with absolutely no image compression, just raw images-to-frames. Using ffmpeg version N-82889-g54931fd, this is what I'm at right now.
ffmpeg -framerate 30 -f image2 -i frames/%02d.png -pix_fmt yuva420p -crf 0 output.webm
The crf 0 flag was told to be the answer, but the output is still full of compression and artifacts. Is there an option to make each frame as close to identical as possible to their corresponding png image frame?

VP8, default encoder for WebM, does not have a lossless mode. Use VP9.
ffmpeg -framerate 30 -i frames/%02d.png -c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 out.webm
Note that due to the pixel format conversion (RGB -> YUV), output will not be perfectly lossless, as there will be some rounding errors when decoding back to RGB.

Related

Speed up reducing size of large JPEG image using ImageMagick

I have a very large JPEG image (10800x7497) that I want to resize down to 50% of its resolution. I have already reduced the image colors down to 64 colors using -define jpeg:colors=64, but when I try resizing the image, ImageMagick takes very long to process the image, probably 20 minutes or more (since I have stopped the process when no output image is saved within 20 minutes, although Task Manager shows ImageMagick processing the image). How can I speed up the resizing of this large image? I have tried the following codes but still it takes too long:
magick -define jpeg:size=10800x7500 "image1.jpg" -resize 5400x3750 "image1-resized.jpg"
magick -define jpeg:size=5400x3750 "image1.jpg" -resize 5400x3750 "image1-resized.jpg"
magick -depth 5 "image1.jpg" -resize 50% "image1-resized.jpg"
It sounds like your imagemagick is swapping to disc. You probably need to adjust your policy.xml.
This is the file containing the limits for the amount of memory and disc magick is allowed to use. The magick docs have some notes, but check /etc/ImageMagick-7/policy.xml and have a look for lines like eg.:
<policy domain="resource" name="memory" value="256MiB"/>
256mb memory use is far too small -- change it something like:
<policy domain="resource" name="memory" value="8GiB"/>
You'll see quite a few other similar lines, adjust them to fit your hardware.
I would simply use resize. The -define hint will turn on jpeg shrink-on-load, which will lose quality and cause (probably) noticeable moire fringing. Plus for a 50% shrink there's no speed benefit.
$ identify big.jpg
big.jpg JPEG 10800x7497 10800x7497+0+0 8-bit sRGB 13.4733MiB 0.000u 0:00.000
$ /usr/bin/time -f %M:%e convert big.jpg -resize 5400x3750 x.jpg
1130340:0.92
So 0.92s and 1.1gb of memory with imagemagick6. imagemagick7 is usually about half the speed and twice the memory use, so I'd expect about 2s and 2GB.
As Mark says, vipsthumbnail is likely to be quicker. I see:
$ /usr/bin/time -f %M:%e vipsthumbnail big.jpg -s 5400 -o x.jpg
295460:0.69
So 300mb of memory and 0.7s. This PC has a stupid number of cores (32!) and you really can't get that much parallelism out of basic JPEG shrinking, so you see a useful speedup and lower memory use if you turn the number of threads down:
$ /usr/bin/time -f %M:%e vipsthumbnail big.jpg -s 5400 -o x.jpg --vips-concurrency=3
77744:0.43
78mb of memory and 0.43s.

Lossless compression of a sequence of similar grayscale images

I would like to have the best compression ratio of a sequence of similar grayscale images. I note that I need an absolute lossless solution (meaning I should be able to check it with an hash algorithm).
What I tried
I had the idea to convert my images into a video because there is a chronology between images. The encoding algorithm would compress using the fact that not all the scene change between 2 pictures. So I tried using ffmpeg but I had several problems due to sRGB -> YUV colorspace compression. I didn't understand all the thing but it's seems like a nightmare.
Example of code used :
ffmpeg -i %04d.png -c:v libx265 -crf 0 video.mp4 #To convert into video
ffmpeg -i video.mp4 %04d.png #To recover images
My second idea was to do it by hand with imagemagik. So I took the first image as reference and create a new image that is the difference between image1 and image2. Then I tried to add the difference image with the image 1 (trying to recover image 2) but it didn't work. Noticing the size of the recreated picture, it's clear that the image is not the same. I think there was an unwanted compression during the process.
Example of code used :
composite -compose difference 0001.png 0002.png diff.png #To create the diff image
composite -compose difference 0001.png diff.png recover.png #To recover image 2
Do you have any idea about my problem ?
And why I don't manage to do the perfect recover with iamgemagik ?
Thanks ;)
Here are 20 samples images : https://cloud.damien.gdn/d/f1a7954a557441989432/
I tried a few ideas with your dataset and summarise what I found below. My calculations and percentages assume that 578kB is a representative image size.
Method 1 - crush - 69%
I just ran pngcrush on one of your images like this:
pngcrush -bruteforce input.png crushed.png
The output size was 400kB, so your image is now only taking 69% of the original space on disk.
Method 2 - rotate and crush - 34%
I rotated your images through 90 degrees and crushed the result:
magick input.png -rotate 90 result.png
pngcrush -bruteforce result.png crushed.png
The rotated crushed image takes 34% of the original space on disk.
Method 3 - rotate and difference - 24%
I rotated your images with ImageMagick, then differenced two adjacent images in the series and saved the result. I then "pngcrushed" that which resulted in 142kB, or 24% of the original space.
Method 4 - combined to RGB - 28%
I combined three of your single channel images into a 3-channel RGB image and pngcrushed the result:
magick 000[123].png -combine result.png
pngcrush -bruteforce result.png crushed.png
That resulted in a 490kB file containing 3 images, i.e. 163kB per image or 28% of the original size.
I suspect video with "motion" estimation/detection would yield the best results if you are able to do it losslessly.
You might get some gain out of MNG, which is intended for lossless animation compression. You can use libmng to try it out.

Difference between 'display_aspect_ratio' and 'sample_aspect_ratio' in ffprobe [duplicate]

I am trying to change the dimensions of the video file through FFMPEG.
I want to convert any video file to 480*360 .
This is the command that I am using...
ffmpeg -i oldVideo.mp4 -vf scale=480:360 newVideo.mp4
After this command 1280*720 dimensions are converted to 640*360.
I have also attached video. it will take less than minute for any experts out there. Is there anything wrong ?
You can see here. (in Video, after 20 seconds, direclty jump to 1:35 , rest is just processing time).
UPDATE :
I found the command from this tutorial
Every video has a Sample Aspect Ratio associated with it. A video player will multiply the video width with this SAR to produce the display width. The height remains the same. So, a 640x720 video with a SAR of 2 will be displayed as 1280x720. The ratio of 1280 to 720 i.e. 16:9 is labelled the Display Aspect Ratio.
The scale filter preserves the input's DAR in the output, so that the output does not look distorted. It does this by adjusting the SAR of the output. The remedy is to reset the SAR after scaling.
ffmpeg -i oldVideo.mp4 -vf scale=480:360,setsar=1 newVideo.mp4
Since the DAR may no longer be the same, the output can look distorted. One way to avoid this is by scaling proportionally and then padding with black to achieve target resolution.
ffmpeg -i oldVideo.mp4 -vf scale=480:360:force_original_aspect_ratio=decrease,pad=480:360:(ow-iw)/2:(oh-ih)/2,setsar=1 newVideo.mp4

How to extract orientation information from videos?

After surfing through tons of documentation on the web it seems that the iPhone always shoots the video at a 480x360 aspect ratio and applies a transformation matrix on the video track. (480x360 may change but its always the same for a given device)
Here is a way of modifying the ffmpeg source within a iOS project and accessing the matrix http://www.seqoy.com/correct-orientation-for-iphone-recorded-movies-with-ffmpeg/
Here is a cleaner way of finding the transformation matrix in iOS-4
How to detect (iPhone SDK) if a video file was recorded in portrait orientation, or landscape.
How can the orientation of the video be extracted in either of the options below -
- iOS 3.2
- ffmpeg (through the command line server side)
- ruby
Any help will be appreciated.
Since most Cameras store their rotation/orientation within the exif-metadata, i would suggest using exifttool and the a ruby wrapper gem called mini_exiftool which is actively maintained.
Install exiftool:
apt-get exiftool || brew install exiftool || port install exiftool
or use what ever package manager is available
Install mini_exiftool:
gem install mini_exiftool
Try it:
irb>
require 'mini_exiftool'
movie = MiniExiftool.new('test_movie.mov')
movie.orientation #=> 90
cheers
You can use ffprobe. No need for any grep, or any other additional processes, or any regex operations to parse the output as shown in other answers.
If you want the rotate metadata:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1:nk=1 input.mp4
Example output:
90
If you want the display matrix rotation side data:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries side_data=rotation -of default=nw=1:nk=1 input.mp4
Example output:
-90
If you want the display matrix:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries side_data=displaymatrix -of default=nw=1:nk=1 input.mp4
Example output:
00000000: 0 65536 0
00000001: -65536 0 0
00000002: 15728640 0 1073741824
What the options mean
-loglevel error Omit the header and other info from output.
-select_streams v:0 Only process the first video stream and ignore everything else. Useful if your input contains multiple video streams and you only want info from one.
-show_entries stream_tags=rotate Chooses to output the rotate tag from the video stream.
-of default=nw=1:nk=1 Use default output format, but omit including the section header/footer wrappers and each field key.
Output format
The output from ffprobe can be formatted in several ways. For example, JSON:
ffprobe -loglevel error -show_entries stream_tags=rotate -of json input.mp4
{
"streams": [
{
"tags": {
"rotate": "90"
},
"side_data_list": [
{
}
]
}
]
From what I've found thus far, ffmpeg doesn't have the ability to detect iPhone's orientation. But, the open source library, mediainfo can. A command line example:
$ mediainfo test.mp4 | grep Rotation
Rotation : 90°
More example output from the same iphone video:
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : Baseline#L3.0
Format settings, CABAC : No
Format settings, ReFrames : 1 frame
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 7s 941ms
Bit rate mode : Variable
Bit rate : 724 Kbps
Width : 480 pixels
Height : 360 pixels
Display aspect ratio : 4:3
Rotation : 90°
Frame rate mode : Variable
Frame rate : 29.970 fps
Minimum frame rate : 28.571 fps
Maximum frame rate : 31.579 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.140
Stream size : 702 KiB (91%)
Title : Core Media Video
Encoded date : UTC 2011-06-22 15:58:25
Tagged date : UTC 2011-06-22 15:58:34
Color primaries : BT.601-6 525, BT.1358 525, BT.1700 NTSC, SMPTE 170M
Transfer characteristics : BT.709-5, BT.1361
Matrix coefficients : BT.601-6 525, BT.1358 525, BT.1700 NTSC, SMPTE 170M
ffmpeg reports the metadata with the rotation value for .mov files:
ffmpeg -i myrotatedMOV.mov
....
Duration: 00:00:14.31, start: 0.000000, bitrate: 778 kb/s
Stream #0:0(und): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p, 480x360, 702 kb/s, 29.98 fps, 30 tbr, 600 tbn, 1200 tbc
Metadata:
rotate : 180
creation_time : 2013-01-09 12:47:36
handler_name : Core Media Data Handler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, s16, 62 kb/s
Metadata:
creation_time : 2013-01-09 12:47:36
handler_name : Core Media Data Handler
In my application I pull it out with regex, ie in python:
import subprocess, re
cmd = 'ffmpeg -i %s' % pathtofile
p = subprocess.Popen(
cmd.split(" "),
stderr = subprocess.PIPE,
close_fds=True
)
stdout, stderr = p.communicate()
reo_rotation = re.compile('rotate\s+:\s(?P<rotation>.*)')
match_rotation = reo_rotation.search(stderr)
rotation = match_rotation.groups()[0]
I havent tried this with a wide range of videos, only a couple .movs recorded from an iphone5, using ffmpeg version 1.0. But so far so good.
Similar to #HdN8's answer, but without the python regex:
$ ffprobe -show_streams any.MOV 2>/dev/null | grep rotate
TAG:rotate=180
Or JSON:
$ ffprobe -of json -show_streams IMG_8738.MOV 2>/dev/null | grep rotate
"rotate": "180",
Or you could parse the JSON (or other output format).
I have extracted on iOS using an AVAssetExportSession, AVMutableComposition and the input AVAssetTrack's preferredTransform. I concatenate the preferred transform with a transformation to fill the target size.
After exporting to a file, I upload using ASIHTTPRequest to my rails server and send the data to Amazon S3 using paperclip.

Graphicsmagick how to forcely covert 32bit image to 24bit bitmap

I would like to force all the input image to be converted into 24bit bmp format. what parameters in gm command line I should add?
gm convert input.png -resize 1920x1080 out.bmp
I think i figured out, just let you guys know
gm convert input.png -resize 1920x1080 +matte out.bmp