안드로이드 mp4 파일 재생 불가 / 회색영상 출력 문제
Django/Python 을 통해 GIF 에서 MP4 변환
Django 기반 SNS 구축 프로젝트를 진행하면서
만약 글쓴이가 gif 파일을 첨부하였다면,
gif를 mp4로 변환하는 기능을 추가하였다.
그런데 문제는 여러가지 gif 파일을 실제 서버에 업로드하여 확인한 결과,
출력이 되는 영상도 있었지만, 영상 재생을 할 수 없거나, 제대로된 영상이 출력되지 않는 문제가 있었다.
변환된 영상을 PC에서도 재생해보고, 모바일에서도 재생해본 결과,
안드로이드 자체에서 지원하는 코덱의 문제임을 확인했다.
기본적으로 안드로이드는 H.264 코덱 중에서도, BP (Base Profile) , MP (Main Profile) 을 지원한다.
여기서 프로파일이란 무엇이냐,
어떤식으로 영상을 압축할지에 대한 기준이라고 볼 수 있다.
결과적으로 GIF 에서 MP4로 변환된 영상의 프로파일이 상기 지원 코덱에 포함되지 않는 것이라 예측 할 수 있다.
이와 같은 결과가 맞는지 확인하기 위해서, ffmpeg 프로그램에서 제공하는 ffprobe를 통해 변환된 영상을 분석해본다.
자세히 보게되면, Higt 4:4:4 Predictive 라는 설명이 나온다.
위키피디아의 목록중 프로파일 번호 244 에 해당하는 압축형식이다.
4:4:4는 크로마 서브샘플링에 관한 표기인데, 궁금하신 분은 개인적으로 찾아보시길 권한다.
이 글에서는 문제 해결에 초점을 맞추도록 하겠다.
결과적으로 이렇게 변환된 mp4 파일을 안드로이드에서 지원하는 BP 혹은 MP 기반의 mp4 파일로 변환해야 한다.
문제 해결 방법
원래 gif 에서 mp4 변환하는 코드의 내용은 이렇다.
...
from moviepy import editor as mp
...
def gif_to_mp4(gif):
"""
Convert gif file to mp4.
returns converted mp4 file path and mp4 file name
"""
if str(gif).split('.')[1] == 'gif':
tt = gif.temporary_file_path()
try:
clip = mp.VideoFileClip(tt)
mp4_name = str(gif.name).replace('.gif', '.mp4')
path = os.path.join(settings.MP4_CONVERT_TEMP_DIR, mp4_name)
clip.write_videofile(path)
except Exception as e:
print(e)
raise Exception('Error occur when converting gif file to mp4')
return path, mp4_name
위 코드 과정은 아래와 같다.
1. Django에서 요청을 받음.
2. request 내의 gif 파일 인스턴스를 확보.
3. gif_to_mp4 함수에 해당 인스턴스를 넘겨줌
4. gif 가 임시 저장되는 임시 폴더 내 경로를 확인
5. 해당 경로의 gif 파일을 읽어들임
6. 영상변환을 위한 임시 경로에 gif 변환후 저장
위의 코드를 꼭 이해하지 않아도 괜찮다.
어차피 위의 과정은 Django 내에서의 흐름이기 때문에 단순히 mp4 변환과는 크게 상관이 없다.
그래서, 결과적으로 해법은,
ffmpeg convert from H.264 (High 4:4:4 Profile) to H.264 (Main Profile)
How can I convert a video from H.264 (High 4:4:4 Profile) to H.264 (Main Profile) using ffmpeg? I can't do that with this command: ffmpeg -i 1/25359.mp4 -profile:v main out.mp4. That'd return an
stackoverflow.com
위 링크에서 확인 할 수 있었다.
4:4:4 프로파일에서 메인 프로파일로 변환하는 방법이 나와있다.
ffmpeg -i 1/25359.mp4 -vf "scale=2*trunc(iw/2):-2,setsar=1" -profile:v main -pix_fmt yuv420p out.mp4
위의 코드를 실제로 앞서 사용한 예제 파일에 적용해보면, ffprobe를 통해 프로파일이 변경된 것을 확인할 수 있다.
그래서 이 ffmpeg 옵션을 기존에 사용하고 있던 moviepy 라이브러리의 메서드에 넘겨주어 같은 작업을 할 수 있도록 해주어야 한다.
결과적으로 코드 한 줄만 변경하면 된다.
clip.write_videofile(path, ffmpeg_params=[
'-vf', 'scale=2*trunc(iw/2):-2,setsar=1',
'-profile:v', 'main',
'-pix_fmt', 'yuv420p'])
위에 있던 코드의 clip.write_videofile 메서드에 아주 친절하게도 ffmpeg_params 라고, ffmpeg 추가적인 옵션을 받아주는 파라미터가 존재한다.
해당 옵션에 3가지 옵션을 넣고 구동하게 되면, 정상적으로 안드로이드, 모바일 크롬에서도 영상이 재생되는 것을 확인할 수 있다.