Base64를 MP4로 디코딩하는 방법
- Base64 또는 data URI에 Base64를 붙여넣으세요.
data:video/mp4;base64,접두사는 그대로 둬도 됩니다. 긴 문자열은 .txt 파일 열기를 사용하세요. 4 MB가 넘으면 텍스트 영역에 표시하지 않고 디코딩합니다. - 플레이어가 클립을 불러옵니다. 브라우저가 인덱스를 읽으면 재생 시간과 크기(가로×세로) 가 나타나며, 예시라면
0:02.0과96 × 64 px입니다. - 안내 영역을 보세요. 진짜 MP4라면 비어 있고, 그렇지 않으면 형식을 알려 줍니다.
- 파일 다운로드를 누르세요.
디코딩과 재생은 브라우저 안에서 이루어지며, 페이지는 Cloudflare 조회수 집계 외에는 네트워크 요청을 할 수 없습니다.
MP4, MOV, M4A: 같은 구조, 여러 형식
MP4 파일은 박스로 이루어져 있으며, 첫 박스인 ftyp에는 파일이 어떤 변형을 따르는지 나타내는 브랜드가 들어 있습니다. 도구는 이 브랜드를 읽습니다.
ftyp의 브랜드 | 감지 결과 | 이 페이지의 안내 |
|---|---|---|
isom, mp41, mp42, avc1, iso6 등 대부분 | MP4 | 없음 |
qt | MOV (QuickTime) | .mov(으)로 다운로드와 함께 “MP4이(가) 아니라 MOV(으)로 보입니다.” |
M4A | M4A | “MP4이(가) 아니라 M4A(으)로 보입니다.”: 오디오만 |
3gp4, 3gp5 등 3g 브랜드 | 3GP, 오래된 휴대폰 동영상 | “MP4이(가) 아니라 3GP(으)로 보입니다.” |
heic, mif1, avif | HEIC, AVIF | “MP4이(가) 아니라 HEIC(으)로 보입니다.”: 같은 박스 구조를 쓰는 정지 이미지 |
브랜드가 MP4인 클립에도 소리만 들어 있을 수 있습니다. 재생은 되며, 크기(가로×세로) 에 오디오만이 표시됩니다. “MP4"로 보낸 WebM 파일은 “MP4이(가) 아니라 WebM(으)로 보입니다.“로 보고됩니다.
인덱스의 위치와 깨진 파일에서 그것이 중요한 이유
모든 MP4에는 각 프레임의 위치를 플레이어에 알려 주는 인덱스인 moov 박스가 있습니다. ffmpeg를 비롯한 많은 인코더는 기본적으로 이를 파일 끝, 즉 mdat의 미디어 데이터 뒤에 씁니다. -movflags +faststart를 주면 ffmpeg가 이를 앞으로 옮기므로, 파일 전체가 도착하기 전에 스트리밍을 시작할 수 있습니다.
이 페이지에서는 파일 전체가 메모리에 있으므로 완전한 클립이라면 위치가 상관없습니다. 위치가 중요해지는 것은 로그, 데이터베이스 열, 메시지 큐의 크기 제한 때문에 Base64가 잘렸을 때입니다.
- 인덱스가 끝에 있으면: 잘리면서 인덱스가 사라져 아무것도 재생되지 않습니다. 첫 바이트는 온전하므로 도구는 여전히 MP4라고 표시하고, 플레이어는 재생할 수 없다고 알리며 재생 시간은 해당 없음으로 나옵니다.
- 인덱스가 앞에 있으면: 브라우저가 인덱스를 읽어 전체 재생 시간을 보여 주고, 데이터가 끝날 때까지 재생합니다.
그러니 짧은 클립은 되는데 긴 클립이 실패한다면, 코덱을 의심하기 전에 디코딩된 크기를 원본과 비교하세요.
Python으로 박스 살펴보기
박스 구조는 라이브러리 없이 훑어볼 수 있을 만큼 단순합니다. 크기 4바이트, 유형 4바이트, 그다음 내용입니다. 다음 코드는 최상위 박스와 브랜드를 나열합니다.
import base64, struct
def mp4_boxes(data):
pos = 0
while pos + 8 <= len(data):
size, kind = struct.unpack(">I4s", data[pos:pos + 8])
if size == 1:
size = struct.unpack(">Q", data[pos + 8:pos + 16])[0]
elif size == 0:
size = len(data) - pos
yield kind.decode("latin-1"), pos, size
if size < 8:
break
pos += size
with open("clip.b64") as f:
data = base64.b64decode(f.read())
for kind, pos, size in mp4_boxes(data):
print(kind, pos, size)
if kind == "ftyp":
body = data[pos + 8:pos + size]
brands = [body[i:i + 4].decode("latin-1") for i in range(8, len(body), 4)]
print(" major:", body[:4].decode("latin-1"), "compatible:", brands)
ffmpeg로 만든 H.264 클립이라면 주 브랜드 isom과 함께 ftyp 0 32를 출력하고, 이어서 free, mdat, 마지막으로 moov가 나옵니다. moov가 mdat보다 앞에 있으면 faststart이고, moof 박스가 있으면 스트리밍용으로 만든 조각화된 MP4입니다. 이 페이지의 예시도 그렇습니다. 목록에 moov가 없다면 파일이 불완전한 것입니다.
브라우저별 코덱 지원은 Base64를 동영상으로를 참고하세요. 클립을 인코딩하려면 MP4를 Base64로를 쓰고, 큰 입력의 디코딩은 Python에서 Base64에서 다룹니다.
자주 묻는 질문
Base64를 MP4 파일로 바꾸려면 어떻게 하나요?
위에 문자열을 붙여넣고 플레이어에서 클립을 확인한 뒤 파일 다운로드를 누르세요. 동영상은 인코딩된 바이트 그대로 decoded.mp4로 저장됩니다.
MP4가 맞는데 재생할 수 없다고 나오는 이유는 무엇인가요?
안에 든 코덱을 브라우저가 지원하지 않거나(가장 흔한 것은 HEVC), 파일이 불완전해 인덱스가 없기 때문입니다. 다운로드한 파일에 ffprobe를 실행하면 둘을 구별할 수 있습니다. 코덱 이름을 알려 주거나, moov 아톰을 찾지 못했다고 보고합니다.
MOV를 .mp4로 저장해도 되나요?
내용에 맞는 확장자인 .mov(으)로 다운로드를 사용하세요. MOV와 MP4는 구조가 대부분 같아서 이름만 바꿔도 실제로는 되는 경우가 많지만, 일부 플레이어는 브랜드를 확인해 맞지 않으면 거부합니다.