SOFTWARE | FFmpeg rotation 설정 renew



iPhone 으로 동영상을 찍다 보면, 휴대폰의 예민한 기울기 센서로 인하여, 자꾸 위아래가 역전되어 찍히는 경우가 있습니다. 이를 다시 보정하려면, FFmpeg 를 활용하면 됩니다.

예전에도 동일한 주제로 확인 했었는데, 그 시절 방법은 이제 먹히지 않는다고 하네요. 그래서, 새로운 방법을 찾던 중, 확실한 솔루션을 찾게 되어 공유 합니다. (아래는 예전 사이트)

* Software | FFmpeg 를 사용하여 동영상을 회전시켜 보자





1. New Options

여러 웹사이트를 찾거나 stack overflow 를 뒤졌으나, 유효하지 않았습니다. 그러던 와중에 FFmpeg 의 버크 티켓팅 사이트를 찾았네요.

* #11649 new defect -noautorotate -display_rotation 0 passes through rotation metadata with JPEG inputs

결국, Metadata 중에서 displaymatrix 라는 친구가 원인인데, 이를 제거하면 되는 것 입니다. 지금까지 알고 있던 command option 은 먹히지 않았습니다.

displaymatrix: rotation of -180.00 degrees

새롭게 소개된 정보는 '-noautorotate -display_rotation 0' 를 이용하여 rotation 관련 Metadata 를 제거하면 되는 것이었습니다. 그러므로 아래와 같이 두번 실행하면 됩니다.

% ffmpeg -noautorotate -display_rotation 0 -i [original_file] -c copy [temporary_file]

% ffmpeg -i [temporary_file] -vf "hflip,vflip" -pix_fmt yuv420p -c:v libx264 -c:a aac [target_file]



2. Check Metadata of Original File

원본 파일을 살펴 보면, 아래와 같이, Side data 섹션에 disaplyamatrix 에서 -180 이 표시됩니다. 이는 뒤집혀서 찍혔다는 것을 의미 합니다.

      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : HEVC
      Side data:
        DOVI configuration record: version: 1.0, profile: 8, level: 5, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 4, compression: 0
        displaymatrix: rotation of -180.00 degrees
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000

'-noautorotate -display_rotation 0' 을 실행시키면, displaymatrix 가 -0.00 로 변경됩니다. Rotation 메타가 삭제된 것이지요.

      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : HEVC
      Side data:
        DOVI configuration record: version: 1.0, profile: 8, level: 5, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 4, compression: 0
        displaymatrix: rotation of -0.00 degrees
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000

마지막으로 -vf "hflip,vflip" 옵션으로 한번 더 실행하면, 실제 동영상이 회전하게 되고, displaymatrix 메타가 사라지게 됩니다.

      Metadata:
        handler_name    : Core Media Video
        vendor_id       : FFMP
        encoder         : Lavc61.19.101 libx264
      Side data:
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A



3. Reset Metadata

실제로 displaymatix 를 삭제한 명령어와 그의 결과 입니다.

-noautorotate -display_rotation 0

% ffmpeg -noautorotate -display_rotation 0 -i IMG_7300.MOV -c copy IMG_7300_01.MOV
ffmpeg version 7.1.1 Copyright (c) 2000-2025 the FFmpeg developers
  built with Apple clang version 17.0.0 (clang-1700.0.13.3)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'IMG_7300.MOV':
  Metadata:
    major_brand     : qt  
    minor_version   : 0
    compatible_brands: qt  
    creation_time   : 2025-03-16T07:40:20.000000Z
    com.apple.quicktime.location.accuracy.horizontal: 15.734295
    com.apple.quicktime.full-frame-rate-playback-intent: 0
    com.apple.quicktime.location.ISO6709: +37.3461+127.0888+077.460/
    com.apple.quicktime.make: Apple
    com.apple.quicktime.model: iPhone 15 Pro Max
    com.apple.quicktime.software: 18.3.2
    com.apple.quicktime.creationdate: 2025-03-16T16:40:20+0900
  Duration: 00:01:07.24, start: 0.000000, bitrate: 13304 kb/s
  Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 1920x1080, 13012 kb/s, 59.95 fps, 59.94 tbr, 600 tbn (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : HEVC
      Side data:
        DOVI configuration record: version: 1.0, profile: 8, level: 5, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 4, compression: 0
        displaymatrix: rotation of -0.00 degrees
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 189 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Audio
        vendor_id       : [0][0][0][0]
  Stream #0:2[0x3](und): Data: none (mebx / 0x7862656D), 0 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Metadata
  Stream #0:3[0x4](und): Data: none (mebx / 0x7862656D), 0 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Metadata
  Stream #0:4[0x5](und): Data: none (mebx / 0x7862656D), 69 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Metadata
  Stream #0:5[0x6](und): Data: none (mebx / 0x7862656D), 5 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Metadata
  Stream #0:6[0x7](und): Data: none (mebx / 0x7862656D), 0 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Metadata
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Output #0, mov, to 'IMG_7300_01.MOV':
  Metadata:
    major_brand     : qt  
    minor_version   : 0
    compatible_brands: qt  
    com.apple.quicktime.creationdate: 2025-03-16T16:40:20+0900
    com.apple.quicktime.location.accuracy.horizontal: 15.734295
    com.apple.quicktime.full-frame-rate-playback-intent: 0
    com.apple.quicktime.location.ISO6709: +37.3461+127.0888+077.460/
    com.apple.quicktime.make: Apple
    com.apple.quicktime.model: iPhone 15 Pro Max
    com.apple.quicktime.software: 18.3.2
    encoder         : Lavf61.7.100
  Stream #0:0(und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 1920x1080, q=2-31, 13012 kb/s, 59.95 fps, 59.94 tbr, 19200 tbn (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : HEVC
      Side data:
        DOVI configuration record: version: 1.0, profile: 8, level: 5, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 4, compression: 0
        displaymatrix: rotation of -0.00 degrees
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 189 kb/s (default)
      Metadata:
        creation_time   : 2025-03-16T07:40:20.000000Z
        handler_name    : Core Media Audio
        vendor_id       : [0][0][0][0]
Press [q] to stop, [?] for help
[out#0/mov @ 0x600000250180] video:106809KiB audio:1558KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.105362%
frame= 4031 fps=0.0 q=-1.0 Lsize=  108482KiB time=00:01:07.20 bitrate=13222.8kbits/s speed=1.04e+03x

Side data 부분의 displaymatix 가 'rotation of -0.00 degrees' 로 변경된 것을 알 수 있습니다.



4. Rotate

메타 정보만 reset 되었을 뿐, 실제 데이터는 뒤집힌 그대로 이므로,  뒤집고 뒤집는 "hflip,vflip" 을 하면 됩니다. 그 이외의 옵션은, browser friendly 한 명령어 -pix_fmt yuv420p 과, video codec 지정인 -c:v libx264, 그리고 audio 는 AAC 를 사용하도록 하는 -c:a aac 입니다.

-vf "hflip,vflip" -pix_fmt yuv420p -c:v libx264 -c:a aac

% ffmpeg -i IMG_7300_01.MOV -vf "hflip,vflip" -pix_fmt yuv420p -c:v libx264 -c:a aac IMG_7300_01.mp4  
ffmpeg version 7.1.1 Copyright (c) 2000-2025 the FFmpeg developers
  built with Apple clang version 17.0.0 (clang-1700.0.13.3)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'IMG_7300_01.MOV':
  Metadata:
    major_brand     : qt  
    minor_version   : 512
    compatible_brands: qt  
    encoder         : Lavf61.7.100
  Duration: 00:01:07.24, start: 0.000000, bitrate: 13215 kb/s
  Stream #0:0[0x1]: Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 1920x1080, 13012 kb/s, 59.95 fps, 59.94 tbr, 19200 tbn (default)
      Metadata:
        handler_name    : Core Media Video
        vendor_id       : FFMP
        encoder         : HEVC
      Side data:
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000
  Stream #0:1[0x2]: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 189 kb/s (default)
      Metadata:
        handler_name    : Core Media Audio
        vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 -> #0:0 (hevc (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
[libx264 @ 0x14770f1e0] using cpu capabilities: ARMv8 NEON
[libx264 @ 0x14770f1e0] profile High, level 4.2, 4:2:0, 8-bit
[libx264 @ 0x14770f1e0] 264 - core 164 r3108 31e19f9 - H.264/MPEG-4 AVC codec - Copyleft 2003-2023 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=21 lookahead_threads=3 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'IMG_7300_01.mp4':
  Metadata:
    major_brand     : qt  
    minor_version   : 512
    compatible_brands: qt  
    encoder         : Lavf61.7.100
  Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt2020nc/bt2020/arib-std-b67, progressive), 1920x1080, q=2-31, 59.94 fps, 60k tbn (default)
      Metadata:
        handler_name    : Core Media Video
        vendor_id       : FFMP
        encoder         : Lavc61.19.101 libx264
      Side data:
        Ambient Viewing Environment, ambient_illuminance=314.000000, ambient_light_x=0.312700, ambient_light_y=0.329000
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
      Metadata:
        handler_name    : Core Media Audio
        vendor_id       : [0][0][0][0]
        encoder         : Lavc61.19.101 aac
[out#0/mp4 @ 0x6000028b4180] video:38072KiB audio:1117KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.278387%
frame= 4031 fps=166 q=-1.0 Lsize=   39298KiB time=00:01:07.21 bitrate=4789.3kbits/s speed=2.77x    
[libx264 @ 0x14770f1e0] frame I:17    Avg QP:22.89  size: 68537
[libx264 @ 0x14770f1e0] frame P:1016  Avg QP:25.47  size: 22711
[libx264 @ 0x14770f1e0] frame B:2998  Avg QP:27.73  size:  4918
[libx264 @ 0x14770f1e0] consecutive B-frames:  0.7%  0.2%  0.9% 98.2%
[libx264 @ 0x14770f1e0] mb I  I16..4: 20.3% 67.6% 12.1%
[libx264 @ 0x14770f1e0] mb P  I16..4:  6.3% 10.3%  0.6%  P16..4: 44.2%  8.1%  2.6%  0.0%  0.0%    skip:27.8%
[libx264 @ 0x14770f1e0] mb B  I16..4:  0.3%  0.6%  0.0%  B16..8: 32.0%  1.1%  0.1%  direct: 0.3%  skip:65.6%  L0:37.6% L1:61.1% BI: 1.3%
[libx264 @ 0x14770f1e0] 8x8 transform intra:60.8% inter:91.5%
[libx264 @ 0x14770f1e0] coded y,uvDC,uvAC intra: 31.6% 42.0% 6.6% inter: 6.1% 7.5% 0.1%
[libx264 @ 0x14770f1e0] i16 v,h,dc,p: 17% 23%  8% 52%
[libx264 @ 0x14770f1e0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 18% 24%  3%  8%  8%  8%  7%  3%
[libx264 @ 0x14770f1e0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 28% 24% 15%  4%  6%  5%  8%  8%  2%
[libx264 @ 0x14770f1e0] i8c dc,h,v,p: 62% 15% 18%  4%
[libx264 @ 0x14770f1e0] Weighted P-Frames: Y:10.2% UV:3.2%
[libx264 @ 0x14770f1e0] ref P L0: 56.6% 20.7% 17.3%  5.1%  0.3%
[libx264 @ 0x14770f1e0] ref B L0: 94.0%  4.9%  1.1%
[libx264 @ 0x14770f1e0] ref B L1: 97.8%  2.2%
[libx264 @ 0x14770f1e0] kb/s:4637.57
[aac @ 0x147777d00] Qavg: 532.633

이제, 완전히 displaymatrix 항목이 없어진 것을 확인할 수 있습니다. 이걸로 고통받는 다른 분들도 참고하시면 좋겠네요.


FIN

댓글