使用FFmpeg旋转视频

558

我一直在尝试使用FFmpeg旋转视频。我正在处理竖屏模式下拍摄的iPhone视频。我知道如何使用MediaInfo(非常好的库)确定当前旋转角度,但现在我遇到了FFmpeg的问题。

根据我所读的,你需要使用vfilter选项。根据我所看到的,它应该是这个样子:

ffmpeg -vfilters "rotate=90" -i input.mp4 output.mp4

然而,我无法使它正常工作。首先,-vfilters不再存在了,现在改为-vf。其次,我遇到了以下错误:

No such filter: 'rotate'
Error opening filters!
据我所知,我拥有一个 FFmpeg 的全选项构建版本。运行 ffmpeg -filters 显示如下内容:
Filters:
anull            Pass the source unchanged to the output.
aspect           Set the frame aspect ratio.
crop             Crop the input video to x:y:width:height.
fifo             Buffer input images and send them when they are requested.
format           Convert the input video to one of the specified pixel formats.
hflip            Horizontally flip the input video.
noformat         Force libavfilter not to use any of the specified pixel formats
 for the input to the next filter.
null             Pass the source unchanged to the output.
pad              Pad input image to width:height[:x:y[:color]] (default x and y:
 0, default color: black).
pixdesctest      Test pixel format definitions.
pixelaspect      Set the pixel aspect ratio.
scale            Scale the input video to width:height size and/or convert the i
mage format.
slicify          Pass the images of input video on to next video filter as multi
ple slices.
unsharp          Sharpen or blur the input video.
vflip            Flip the input video vertically.
buffer           Buffer video frames, and make them accessible to the filterchai
n.
color            Provide an uniformly colored input, syntax is: [color[:size[:ra
te]]]
nullsrc          Null video source, never return images.
nullsink         Do absolutely nothing with the input video.

虽然拥有vfliphflip选项很好,但它们并不能满足我的需求。我需要能够旋转视频至少90度的功能。如果还有270度的选项,那就更好了。旋转选项去哪里了?


101
寻找需要进行180度旋转的人,可以使用参数“-vf"vflip,hflip"”来实现水平和竖直翻转。 - OrangeDog
7
我在想,是否可以在不解码和重新编码视频的情况下实现这一点--就像jpegtran可以无损旋转JPEG图像一样... - Mikhail T.
2
请点击此处查看旋转标志:https://dev59.com/Z2Up5IYBdhLWcg3wVWmv - Davor Josipovic
2
还可以查看如何使用FFmpeg将视频翻转180°(垂直/倒置)?的详细答案。不要忘记重置任何现有的旋转元数据(请参见链接)。 - llogan
1
我刚刚上传了一个使用“transpose=1,transpose=1”进行了180度旋转的视频到vimeo。尽管我可以播放旋转后的视频,但它被vimeo拒绝了。@OrangeDog的方法“-vf“vflip,hflip””非常有效。 - Besi
显示剩余6条评论
16个回答

923

顺时针旋转90度:

ffmpeg -i in.mov -vf "transpose=1" out.mov

对于转置参数,您可以传递:

0 = 90° counterclockwise and vertical flip (default)
1 = 90° clockwise
2 = 90° counterclockwise
3 = 90° clockwise and vertical flip

使用-vf "transpose=2,transpose=2"进行180度旋转。

确保您使用最新的FFmpeg版本(从这里)(静态构建将正常工作)。

请注意,这将重新编码音频和视频部分。通常可以通过使用-c:a copy来复制音频而不触及它。要更改视频质量,请设置比特率(例如使用-b:v 1M)或查看H.264编码指南以获取VBR选项。

另一种解决方案是使用此便捷脚本


13
视频仍将保留方向信息,因此现在在 iPhone 上观看视频时会出现方向不正确的情况。 - srcspider
34
当我使用这个命令时,输出的视频质量很差,除非 -- 就像我刚发现的那样 -- 我也使用这个参数:-vcodec libx264。但如果 ffmpeg 已经知道要使用哪种编码,那就好了。你有什么建议吗? - Sadi
11
跟Sadi提到的类似,有没有一种方法可以“复制”原始视频的质量? - Alec Jacobson
65
可以使用“-vf“选项,并设置值为”transpose=2,transpose=2“,来进行180度视频旋转。 - Alex Pliutau
32
当前文档指出:“数值已不建议使用,应该改为使用符号常量。” http://ffmpeg.org/ffmpeg-filters.html#transpose 因此,在使用0123之前应使用cclock_flipclockcclockclock_flip - l --marc l
显示剩余20条评论

240
如果您不想重新编码视频,并且您的播放器可以处理旋转元数据,您可以使用FFmpeg更改元数据中的旋转角度,使用标志display_rotation和值090180270
ffmpeg -display_rotation 90 -i input.mp4 -codec copy output.mp4

不支持标志display_rotation的旧版本FFmpeg可以使用以下标志修改元数据:

ffmpeg -i input.mp4 -map_metadata 0 -metadata:s:v rotate="90" -codec copy output.mp4

18
先用 ffmpeg -i input.m4v 2>&1 | grep rotate 检查旋转元数据怎么样? - lidaobing
102
这是迄今为止最好的答案,但还有一点需要改进。为了避免视频上丢失其余的元数据(例如日期、相机),请执行 ffmpeg -i input.m4v -map_metadata 0 -metadata:s:v rotate="90" -codec copy output.m4v。这样输入文件的所有全局元数据都将复制为输出文件的全局元数据,并且只更改旋转元数据。 - migle
18
如果您有一个肖像模式的视频并且只想将其“取消旋转”以获得标准的1920x1080像素,那么您可能需要使用“rotate=0”。 - mivk
2
尝试了-metadata:s:v rotate="180",但没有起作用。那应该可以起作用吗? - Ondra Žižka
11
我认为这是最好的解决方案,因为不需要重新编码,并且大多数视频播放器支持元数据旋转。另外像谷歌相册这样的云服务也是如此。 但请记住,ffmpeg不一定会将所有元数据从原始文件复制过来! 因此,我建议显式指定将所有其他元数据从原始文件复制过来: ffmpeg -i input.mp4 -codec copy -map_metadata 0 -metadata:s:v:0 rotate=0 output.mp4 - Andreas
显示剩余16条评论

102
使用transpose。就像(来自其他答案):
 ffmpeg -i input -vf transpose=2 output

如果您正在使用旧版本,则必须更新FFmpeg才能使用转置功能,因为该功能是在2011年10月添加的。

FFmpeg下载页面提供了静态构建版本,您可以直接执行而无需编译。


1
不,我没有。我不知道它的存在。我会试一试。 - jocull
10
感觉好像因为在被采纳的答案出现前1.5年提供了有用的答案,而受到了惩罚。 - rwilliams
1
如果有多个过滤器,这该怎么办?-vf transpose=2 crop=20:20?因为-vf transpose=2 -vf crop=20:20会忽略旋转(transpose)。编辑: -vf transpose=2 crop=20:20没有起作用。 - Jonas Borggren
2
@JonasB 用逗号分隔过滤器。请参阅https://dev59.com/y2025IYBdhLWcg3wIyOf - rwilliams
4
虽然这是一个很好的答案,并且比Alexy的答案早了1.5年,但它的缺点是没有包括有关转置操作的更多信息或如何使用它的信息。你提供链接是很好的,但链接到相关信息的缺点是(就像在这种情况下一样)链接不再指向正确的文档。如果没有其他问题,我会提交编辑以修复链接。 - bmaupin
显示剩余4条评论

27

要将图片顺时针旋转,您可以使用旋转滤镜,指定一个正的弧度角。由于90度等于π/2,您可以这样做:

ffmpeg -i in.mp4 -vf "rotate=PI/2" out.mp4

对于逆时针旋转,角度必须为负数

ffmpeg -i in.mp4 -vf "rotate=-PI/2" out.mp4

转置滤镜对于90度的旋转同样有效,但对于其他角度来说,这是更快或唯一的选择。


2
这太棒了。我发现可以获得更细粒度的弧度分辨率,因为 * 的行为类似于乘法:ffmpeg -i in.avi -vf“rotate=-8*PI/40”-q 1 out.avi(旋转角度略小于-PI/4 = -10 * PI / 40)。 - eqzx

21

我在搜索同样的答案时发现了这个页面。现在距最初的提问已经过去了六个月,构建已经更新了很多次。但是,我想为任何其他人添加一个答案,他们在此处寻找此信息。

我正在使用 Debian 6.0(Squeeze)和从那些软件源中下载的 FFmpeg 版本。

FFmpeg手册页面说明如下用法:

ffmpeg -i inputfile.mpg -vf "transpose=1" outputfile.mpg

重点是您不应使用度变量,而是使用来自手册的预定义设置变量。
0=90CounterCLockwise and Vertical Flip  (default)
1=90Clockwise
2=90CounterClockwise
3=90Clockwise and Vertical Flip

谢谢提供这些信息!我之前一直无法让它正常工作,因为我通常在从源代码构建时遇到麻烦。现在我可能会再试试看能否让它正常工作。 - jocull
transpose=3 会导致图像镜像。 - Daniel Kobe
转置=2 对我旋转270度的视频进行了处理,没有镜像。 - Daniel Kobe

12
ffmpeg -vfilters "rotate=90" -i input.mp4 output.mp4

即使使用最新的源代码,也无法工作...

您必须更改顺序:

ffmpeg -i input.mp4 -vf vflip output.mp4

它工作得很好。


因为你将滤镜应用到了错误的文件上...试试使用 ffmpeg -i input.mp4 -vf "rotate=90" output.mp4 命令,然后它就可以工作了。 - patrick
4
将视频以__弧度__为单位旋转任意角度。文档:http://ffmpeg.org/ffmpeg-filters.html#rotate 因此,需要使用弧度 rotate=PI/2rotate=90*PI/180 - l --marc l

8
如果你遇到了“Codec is experimental but experimental codecs are not enabled”错误,请使用以下方法:
ffmpeg -i inputFile -vf "transpose=1" -c:a copy outputFile

发生在我身上的问题是某些带有AAC音频的.mov文件。

这是唯一对我有效的示例,但质量很差,而且非常粗糙。此外,它将1080x1920的视频缩小到了352x640。我想我可能缺少一两个开关。有什么建议吗? - LOlliffe
2
@LOlliffe 添加 -sameq - Andrew Schleifer
2
@AndrewSchleifer 谢谢。我试过了,但是ffmpeg给我返回了选项'sameq'已被删除。如果您正在寻找保留质量的选项(这不是-sameq的作用),请使用-qscale 0或等效的质量因子选项。 无法为选项'sameq'设置值'1':无效参数 -qscale也会出错。请使用-q:a或-q:v,-qscale不明确,但仍然有效。 - LOlliffe

6
另一种解决方案与前面提到的解决方案不同,是检查您的摄像头驱动程序是否支持v4l2相机控件(这非常普遍)。在终端中,只需键入:
v4l2-ctl -L

如果您的相机驱动程序支持v4l2相机控件,您应该会得到类似这样的内容(下面的列表取决于您的相机驱动程序所支持的控件):
               contrast (int)    : min=0 max=255 step=1 default=0 value=0 flags=slider
             saturation (int)    : min=0 max=255 step=1 default=64 value=64 flags=slider
                    hue (int)    : min=0 max=359 step=1 default=0 value=0 flags=slider
white_balance_automatic (bool)   : default=1 value=1 flags=update
            red_balance (int)    : min=0 max=4095 step=1 default=0 value=128 flags=inactive, slider
           blue_balance (int)    : min=0 max=4095 step=1 default=0 value=128 flags=inactive, slider
               exposure (int)    : min=0 max=65535 step=1 default=0 value=885 flags=inactive, volatile
         gain_automatic (bool)   : default=1 value=1 flags=update
                   gain (int)    : min=0 max=1023 step=1 default=0 value=32 flags=inactive, volatile
        horizontal_flip (bool)   : default=0 value=0
          vertical_flip (bool)   : default=0 value=0

如果你很幸运,它支持horizontal_flipvertical_flip
那么你所需要做的就是通过以下方式设置horizontal_flip

v4l2-ctl --set-ctrl horizontal_flip=1

或者通过 vertical_flip 实现垂直翻转:

v4l2-ctl --set-ctrl vertical_flip=1

然后您可以调用视频设备来捕获新视频(请参见下面的示例),视频将被旋转/翻转。

ffmpeg -f v4l2 -video_size 640x480 -i /dev/video0 -vcodec libx264 -f mpegts input.mp4

当然,如果您需要处理已经存在的视频,则此方法不是您要寻找的解决方案。

这种方法的优点在于我们在传感器级别上翻转图像,因此驱动程序的传感器已经为我们提供了翻转的图像,这样可以节省应用程序(如FFmpeg)进一步且不必要的处理。


1
这里有关于v4l2的很棒的信息。在录制时旋转到正确的方向显然是更可取的:) 这个将近10年的问题(哇!)最初是关于从iOS设备上传视频的,如果这能提供任何背景信息 :) - jocull
我在这个社区还比较新,而且这个问题比我在这里的资历要老得多... 我真的认为这是一个好(也很常见)的问题,所以我相信这个老问题会继续帮助许多FFmpeg用户。 - J.M.

3

默认情况下,ffmpeg.exe旋转滤镜可能会裁剪图像。为了保持原始窗口的宽度和高度,在逆时针旋转90°时,可以使用以下命令:

ffmpeg.exe -i infilename -vf rotate=-PI/2:oh=iw:ow=ih outfilename

通过添加:oh=iw:ow=ih,它指定[out window width]=[input window height],[out window width]=[input window height]。这相当于-vf transpose=2,旋转而不裁剪图像。
在这里:
iw: input width
ih: input height
ow: output width
oh: output height

请查看 11.210旋转

PI/2重复为我执行一个180度顺时针旋转。我正在使用同一播放器进行输入和输出,所以不确定可能出现了什么问题... - NeilG

3
此脚本将输出“fixedFiles”目录结构下的文件。目前仅固定于MOV文件,并根据视频原始“旋转”的情况执行多个变换。它适用于在运行Mac OS X v10.9(Mavericks)的 Mac 上捕获的 iOS 视频,但应易于导出。它依赖于已安装ExifToolFFmpeg
#!/bin/bash

# Rotation of 90 degrees. It will have to concatenate.
#ffmpeg -i <originalfile> -metadata:s:v:0 rotate=0 -vf "transpose=1" <destinationfile>
#/VLC -I dummy -vvv <originalfile> --sout='#transcode{width=1280,vcodec=mp4v,vb=16384,vfilter={canvas{width=1280,height=1280}:rotate{angle=-90}}}:std{access=file,mux=mp4,dst=<outputfile>}\' vlc://quit

# Allowing blanks in file names
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

# Bit Rate
BR=16384

# Where to store fixed files
FIXED_FILES_DIR="fixedFiles"
#rm -rf $FIXED_FILES_DIR
mkdir $FIXED_FILES_DIR

# VLC media player
VLC_START="/Applications/VLC.app/Contents/MacOS/VLC -I dummy -vvv"
VLC_END="vlc://quit"


#############################################
# Processing of MOV in the wrong orientation
for f in `find . -regex '\./.*\.MOV'`
do
  ROTATION=`exiftool "$f" |grep Rotation|cut -c 35-38`
  SHORT_DIMENSION=`exiftool "$f" |grep "Image Size"|cut -c 39-43|sed 's/x//'`
  BITRATE_INT=`exiftool "$f" |grep "Avg Bitrate"|cut -c 35-38|sed 's/\..*//'`
  echo Short dimension [$SHORT_DIMENSION] $BITRATE_INT

  if test "$ROTATION" != ""; then
    DEST=$(dirname ${f})
    echo "Processing $f with rotation $ROTATION in directory $DEST"
    mkdir -p $FIXED_FILES_DIR/"$DEST"

    if test "$ROTATION" == "0"; then
      cp "$f" "$FIXED_FILES_DIR/$f"

    elif test "$ROTATION" == "180"; then
#      $(eval $VLC_START \"$f\" "--sout="\'"#transcode{vfilter={rotate{angle=-"$ROTATION"}},vcodec=mp4v,vb=$BR}:std{access=file,mux=mp4,dst=\""$FIXED_FILES_DIR/$f"\"}'" $VLC_END )
      $(eval ffmpeg -i \"$f\" -vf hflip,vflip -r 30 -metadata:s:v:0 rotate=0 -b:v "$BITRATE_INT"M -vcodec libx264 -acodec copy \"$FIXED_FILES_DIR/$f\")

    elif test "$ROTATION" == "270"; then
      $(eval ffmpeg -i \"$f\" -vf "scale=$SHORT_DIMENSION:-1,transpose=2,pad=$SHORT_DIMENSION:$SHORT_DIMENSION:\(ow-iw\)/2:0" -r 30 -s "$SHORT_DIMENSION"x"$SHORT_DIMENSION" -metadata:s:v:0 rotate=0 -b:v "$BITRATE_INT"M -vcodec libx264 -acodec copy \"$FIXED_FILES_DIR/$f\" )

    else
#      $(eval $VLC_START \"$f\" "--sout="\'"#transcode{scale=1,width=$SHORT_DIMENSION,vcodec=mp4v,vb=$BR,vfilter={canvas{width=$SHORT_DIMENSION,height=$SHORT_DIMENSION}:rotate{angle=-"$ROTATION"}}}:std{access=file,mux=mp4,dst=\""$FIXED_FILES_DIR/$f"\"}'" $VLC_END )
      echo ffmpeg -i \"$f\" -vf "scale=$SHORT_DIMENSION:-1,transpose=1,pad=$SHORT_DIMENSION:$SHORT_DIMENSION:\(ow-iw\)/2:0" -r 30 -s "$SHORT_DIMENSION"x"$SHORT_DIMENSION" -metadata:s:v:0 rotate=0 -b:v "$BITRATE_INT"M -vcodec libx264 -acodec copy \"$FIXED_FILES_DIR/$f\"
      $(eval ffmpeg -i \"$f\" -vf "scale=$SHORT_DIMENSION:-1,transpose=1,pad=$SHORT_DIMENSION:$SHORT_DIMENSION:\(ow-iw\)/2:0" -r 30 -s "$SHORT_DIMENSION"x"$SHORT_DIMENSION" -metadata:s:v:0 rotate=0 -b:v "$BITRATE_INT"M -vcodec libx264 -acodec copy \"$FIXED_FILES_DIR/$f\" )

    fi

  fi

echo
echo ==================================================================
sleep 1
done

#############################################
# Processing of AVI files for my Panasonic TV
# Use ffmpegX + QuickBatch. Bitrate at 16384. Camera res 640x424
for f in `find . -regex '\./.*\.AVI'`
do
  DEST=$(dirname ${f})
  DEST_FILE=`echo "$f" | sed 's/.AVI/.MOV/'`
  mkdir -p $FIXED_FILES_DIR/"$DEST"
  echo "Processing $f in directory $DEST"
  $(eval ffmpeg -i \"$f\" -r 20 -acodec libvo_aacenc -b:a 128k -vcodec mpeg4 -b:v 8M -flags +aic+mv4 \"$FIXED_FILES_DIR/$DEST_FILE\" )
echo
echo ==================================================================

done

IFS=$SAVEIFS

4
哎呀... 这个脚本或许能用,但是它看起来真的太糟糕了。首先,作为 shell 编程的基本准则:在管道中永远不需要用到 grep、cut、awk 和 sed 中的超过一个。任意一个 grep|cut|sed 的操作都可以只用 sed 或者 awk 单独完成。另外,更具体地说,exiftool 可以输出你所需要的标签 -- 所以不必再去过滤旋转标签,直接使用 "exiftool -Rotation" 命令即可。 第三,在代码的可读性和效率方面,你也并不需要这么多的 "eval" 语句,而且 "if test..." 语句可以替换为 case $ROTATION in 语句。 祝好运! - Mikhail T.
无法进行操作:[Parsed_pad_2 @ 0x7f8b15c3a580] 输入区域 -420:0:1500:1080 不在填充区域 0:0:1080:1080 或大小为零\n [Parsed_pad_2 @ 0x7f8b15c3a580] 无法配置 Parsed_pad_2 的输入端\n 重新初始化过滤器时出错!\n 无法将帧注入到过滤器网络中:参数无效\n 处理流 #0:0 的解码数据时出错\n 转换失败!` - Slipp D. Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接