image -> video -> image not lossless using avconv - codec

I'm trying to test the amount of information lost with some different video codecs. I've got a python script which uses PyPNG to write a series of 8 bit RGB images. I then encode it using avconv, for instance
avconv -r 1 -i ../frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1
outffv1.avi
I then decode this back into pngs like so
avconv -r 1 -i outffv1.avi -r 1 ./outffv1/frame%03d.png
But when I compare the images before and after the video compression, they are different (mean absolute error of ~~15%). The thing that is confusing me is that this is true (give or take) independent of the codec.
For instance, I get similar answers for libtheora for a range of qscale values.
The png encoding i.e. write to png, and immediately load back in without and video compression step, is lossless.
UPDATE - more precise worked example:
Single input frame here: https://www.dropbox.com/s/2utk1xs2t8heai9/data001.png?dl=0
Encoded to video like this: avconv -r 1 -i ./frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1 outffv1.avi
resultant video here: https://www.dropbox.com/s/g1babae2a41v914/outffv1.avi?dl=0
decoded to a png again here: https://www.dropbox.com/s/8i8zg1qn7dxsgat/out001.png?dl=0
using this command: avconv -r 1 -i outffv1.avi -qscale:v 31 -r 1 out%03d.png
and image magick differenced like this
compare out001.png ./frames/data001.png diff.png
to give this (non-zero) diff
https://www.dropbox.com/s/vpouk54p0dieqif/diff.png?dl=0

Your video file most likely uses the YUV color format. PNG uses RGB. The conversion of the color is not a lossless process.

Related

How to map pixel or point units to ffmpeg font / text size

I have a web page form where I take text size in pixel or point units pass to ffmpeg and run ffmpeg command to set text size but they don't match. what is the ffmpeg text size standard unit or is there any way I can convert pixels or units into ffmpeg text size so they don't differ.
The fontsize parameter in drawtext filter is passed onto the freetype library which is actually responsible for drawing the characters. The closest you can come to mapping the fontsize to pixel units using the ffmpeg runtime is to print
ffmpeg -v 24 -hide_banner -f lavfi -i color -vf "drawtext=/path/to/font:fontsize=1000:text='A':x=W/2:y=print(th\,24)" -vframes 1 -f null -
This will print the height, in pixels, that the uppercase 'A' occupies for a fontsize of 1000 using the specified font. Different fonts have different scales.

Splitting m4a into multiple files with ffmpeg

I have an audio file (.m4a) and want to split it into smaller pieces using ffmpeg. All answers I have seen do something along one of the following two possibilities:
ffmpeg -i inputFile -map 0 -f segment -segment_time 60 -c copy "$output%03d.m4a
or
ffmpeg -i inputFile -acodec copy -ss start_time -to end_time outputFile
With 1. the first file is fine. From the second file on, I just get a minute of silence in quicktime, and in VLC the file plays but the timing is odd: for example the second file should have second 0 equals to second 60 in the original file. However in vlc it starts playing on second 60 and goes on to second 120.
With 2. I have to set start times and end for each file, unfortunately I notice a small jump when I play one after the other, so it seems as if some miliseconds are lost.
There are definitely a few old questions asked around this, but none of them actually helped me with this.
Quicktime probably doesn't like files starting with a timestamp other than 0.
Use
ffmpeg -i inputFile -map 0 -f segment -segment_time 60 -reset_timestamps 1 -c copy "$output%03d.m4a

How to keep the orientation number(exif) after converting from a video file to a image file by a ffmpeg command

The command below is working perfectly fine for my environment except it deletes the orientation number(exif) of the image file after being converted from a video file.
I'd like to know how to keep the orientation number(exif) of the image with the command line below(it also have to keep the original purpose of its functionality which is to convert a video to a image from one directory to another.). I'd appreciate if anyone could help me out.
for i in /path/to/inputs/*.mp4; do ffmpeg -i "$i" -frames:v 1 "/path/to/outputs/$(basename "$i" .mp4).jpg"; done
ffmpeg version 2.2.2
OS:centos-6 (x86_64)
tl;dr
Update your ffmpeg and it will automatically rotate then you won't have to deal with exif tags.
rotate side data
MP4 does not contain exif data, but it can contain rotate side data. This is information a player can use to properly orient the video (not all players or devices support this), even if the video stream itself is not oriented as such. Videos from iPhones for example have this side data.
ffmpeg auto-rotates
When encoding, ffmpeg will by default automatically rotate the output depending on the rotate side data. So you may not need to set the exif orientation tag at all. You can disable this behavior by using the -noautorotate option. Note that your ffmpeg (version 2.2) is too old for this behavior and this option, so it does not automatically rotate. I recommend you download a recent ffmpeg version and move it to /usr/local/bin.
So, given that non-ancient ffmpeg will automatically rotate do you even need to deal with the exif orientation tag? If you answer "yes" then see the sections below.
viewing rotate side data in MP4 video
You can use ffprobe to view the rotate side data of the input video:
ffprobe -loglevel error -select_streams v:0 -show_entries side_data=rotation -of csv=p=0 input.mp4
setting exif orientation tag in JPG image
You can use exiftool to write the orientation exif tag to the JPG image:
exiftool -Orientation=6 -n image.jpg
Or a human readable form:
exiftool -Orientation='Rotate 90 CW' image.jpg
Numerical Orientation values are:
1 = Horizontal (normal)
2 = Mirror horizontal
3 = Rotate 180
4 = Mirror vertical
5 = Mirror horizontal and rotate 270 CW
6 = Rotate 90 CW
7 = Mirror horizontal and rotate 90 CW
8 = Rotate 270 CW
As for implementing this in your bash script I think that's worth asking as a separate question.
viewing exif orientation tag in JPG image
You can use exiftool to view the orientation:
$ exiftool -Orientation -S image.jpg
Orientation: Rotate 90 CW
$ exiftool -Orientation -n -S image.jpg
Orientation: 6

Why the Target Duration of the created segments are not the one i specified

I am using the following command
ffmpeg -i Apple.ts -map 0:0 -map 0:1 -c copy -f segment -segment_time 10 -segment_list test.m3u8 -segment_format ts 'fileSequence%d.ts'
The files do get segmented but the values are not precise. see in the .m3u8 generated below the target duration is 12 but i specified 10
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOWCACHE:1
#EXTINF:11.478100,
fileSequence0.ts
#EXTINF:10.410400,
fileSequence1.ts
#EXTINF:11.745067,
fileSequence2.ts
#EXTINF:7.841167,
fileSequence3.ts
#EXTINF:8.024678,
fileSequence4.ts
#EXT-X-TARGETDURATION:12
#EXT-X-ENDLIST
Also if i dont want the floting point duration how do i do it?
To get strict duration you need to ensure your input file has been encoded with a strict I picture rate. Ensure you have set keyframe interval to 10 seconds and sc_threshold to 0 while encoding the original mp4.with ffmpeg. Then run your segmentation command. This will give you exact 10 second segments.
Otherwise ffmpeg will try and cut around the 10 second mark ( or whatever duration you have given ) at the closes I picture it can find.

cut exact time range from mp3/ogg

I have a heap of audio files on a CDN. Those are mp3's and ogg vorbises, in parallel. Those files are each worth about one hour of playback. I need to extract arbitrary parts from those files: I am given a filename (I can choose if I use the mp3 or ogg version) and two timestamps and I need the audio exactly between the given time positions. I don't want to download the whole file, so I think of using the Range http header.
I have complete control over the audio files, so I encoded them in fixed bitrate, to be able to estimate which bytes I should reach for. However, both formats use frames (or pages in vorbis's case), which must be decoded atomically.
The program I write is in Perl. I tried downloading a part of the file where I believe the given window to be contained, and then using Audio::Mad and Ogg::Vorbis::Decoder to parse the audio file fragments. However, both seem to fail to process the fragments, and only succeed when I serve an integral file.
So my question is: How can I get an exact span of an audio file without downloading the whole thing?
Answering "cut exact time range from mp3/ogg" - You can check out if the following fits Your needs:
ffmpeg -i InFile -vn -acodec copy -ss 00:00:00 -t 00:01:32 -threads 0 OutFile
where ss - start time, t - duration. It cuts indeed - no re-compressions.

Resources