FFMPEG: crop a video without losing the quality
Solution 1
You can't perform any filtering without losing quality when encoding to a lossy format, but you have some options.
Crop with your player
A possible solution would be to crop during playback, so you don't even need to re-encode. It is also useful to preview a crop.
This method will not create an output file. This will use your video player to crop while it is playing. See one of the other methods below if you want an output file.
With ffplay
and crop filter:
ffplay -vf "crop=480:270:200:100" input.mp4
With vlc
(or cvlc
):
vlc input.mp4 --crop=480x270+200+100
Or you could crop with the VLC GUI: Tools → Effects & Filters → Video Effects → Crop.
Accept some quality loss (you may not even notice a difference)
Give it enough bits and you may not be able to tell there is a quality difference:
ffmpeg -i input -vf "crop=480:270:200:100" -c:v libx264 -crf 17 -c:a copy ouput.mp4
See FFmpeg Wiki: H.264 Video Encoding Guide for more info.
Use a bitstream filter
The h264_metadata and hevc_metadata bitstream filters can set crop dimensions without modifying the video itself.
Note: Your player may not support this method.
Example for H.264 video:
ffmpeg -i input.mp4 -c copy -bsf:v h264_metadata=crop_left=100:crop_right=20:crop_top=10:crop_bottom=10 output.mp4
-
Sets the frame cropping offsets in the SPS. These values will replace the current ones if the stream is already cropped.
-
These fields are set in pixels. Note that some sizes may not be representable if the chroma is subsampled or the stream is interlaced (see H.264 section 7.4.2.1.1).
Use a lossless format
ffmpeg
can encode with several lossless encoders: ffv1, huffyuv, ffvhuff, utvideo, libx264 (using -crf 0
or -qp 0
). The output will be lossless but the output file will be huge.
Note: Your player may not support this method.
ffmpeg -i input.mp4 -vf "crop=480:270:200:100" -c:v ffv1 -c:a copy output.mkv
or
ffmpeg -i input.mp4 -vf "crop=480:270:200:100" -c:v libx264 -crf 0 -c:a copy output.mp4
If your input is MJPEG
Stream copy the individual images with ffmpeg
, crop them losslessly with jpegtran
, then remux them with ffmpeg
. This will result in no loss, but you will be restricted to the ancient MJPEG format.
Solution 2
At a basic level you cannot make use of a lossy encoding and then expect it to not lose quality when you decode and then encode again. The only way that works is to make use of a lossless codec, for example Quicktime with the Animation codec. This is just a basic truth of digital video production that you cannot work around by just passing command line options to ffmpeg.
Solution 3
This is not possible using ffmpeg.
As alternative you can embed your video in a Matroska (.mkv) container and set a cropping tag in the file header, but it must be supported by your player.
Reportedly, for H264-encoded videos H264info can also be used, but i still need to figure out how to use it...
Solution 4
For some video formats at least, the soft solution based on metadata should be possible with FFmpeg as well by using bitstream filters from libavcodec, e.g. hevc_metadata
or h264_metadata
.
Unlike filters like crop
and cropdetect
, this does not require decoding. The syntax slightly differs, though, because you can only set the amount of cropping from the four edges, not the target rectangle size. For the OP's 480×270 area at position (200,200) from the top left in a 1920×1080 full HD frame, we get:
ffmpeg -i input.mp4 -codec copy -bsf:v h264_metadata=crop_left=200:crop_right=1240:crop_top=200:crop_bottom=610 output.mp4
Since this is codec metadata, this should work regardless the container format, i.e. not just in MP4, but in MKV or AVI as well. Alas, I have not tested it myself yet and cannot say anything about support in software and hardware players. (A first simple check failed miserably, though.)
For more detailed info, FFmpeg's documentation refers to sections 7.4.3.2.1 and 7.4.2.1.1 of the H.265 and H.264 specifications respectively, which are freely available from ITU and are basically equivalent:
frame_cropping_flag
equal to 1 specifies that the frame cropping offset parameters follow next in the sequence parameter set. frame_cropping_flag equal to 0 specifies that the frame cropping offset parameters are not present.
frame_crop_left_offset
,frame_crop_right_offset
,frame_crop_top_offset
,frame_crop_bottom_offset
specify the samples of the pictures in the coded video sequence that are output from the decoding process, in terms of a rectangular region specified in frame coordinates for output. The variablesCropUnitX
andCropUnitY
are derived as follows:– If ChromaArrayType is equal to 0, CropUnitX and CropUnitY are derived as:
CropUnitX = 1
CropUnitY = 2 − frame_mbs_only_flag
– Otherwise (ChromaArrayType
is equal to 1, 2, or 3),CropUnitX
andCropUnitY
are derived as:CropUnitX = SubWidthC
CropUnitY = SubHeightC * ( 2 − frame_mbs_only_flag )
The frame cropping rectangle contains luma samples with horizontal frame coordinates from
CropUnitX * frame_crop_left_offset to PicWidthInSamplesL − ( CropUnitX * frame_crop_right_offset + 1 )
and vertical frame coordinates fromCropUnitY * frame_crop_top_offset to ( 16 * FrameHeightInMbs ) − ( CropUnitY * frame_crop_bottom_offset + 1 )
, inclusive.The value of
frame_crop_left_offset
shall be in the range of 0 to( PicWidthInSamplesL / CropUnitX ) − ( frame_crop_right_offset + 1 )
, inclusive; and the value offrame_crop_top_offset
shall be in the range of 0 to( 16 * FrameHeightInMbs / CropUnitY ) − ( frame_crop_bottom_offset + 1 )
, inclusive.When
frame_cropping_flag
is equal to 0, the values offrame_crop_left_offset
,frame_crop_right_offset
,frame_crop_top_offset
, andframe_crop_bottom_offset
shall be inferred to be equal to 0.When
ChromaArrayType
is not equal to 0, the corresponding specified samples of the two chroma arrays are the samples having frame coordinates( x / SubWidthC, y / SubHeightC )
, where( x, y )
are the frame coordinates of the specified luma samples.For decoded fields, the specified samples of the decoded field are the samples that fall within the rectangle specified in frame coordinates.
![mrana](https://lh6.googleusercontent.com/-tf59vl0Use8/AAAAAAAAAAI/AAAAAAAAATY/RTX4YYio934/photo.jpg?sz=256)
mrana
Updated on July 09, 2022Comments
-
mrana almost 2 years
I have mp4 video of
1920x1080
. I would like to crop the video to480x270
without quality loss.I am using the following command:
ffmpeg -i input.mp4 -filter:v "crop=480:270:200:200" -crf 23 output.mp4
I also tried:
ffmpeg -i input.mp4 -filter:v "crop=480:270:200:100" -c:a copy -qp 0 output.mp4
I used
-crf 23
and-qp 0
for loseless video cropping, but after cropping video has lost quality.Does anyone know how I can crop the video without losing the quality?