Skip to content

How do I load and store an mp4 video file? #1069

@anna-charlotte

Description

@anna-charlotte

Overview

I want to have two functions:

  • one to load a video array from an .mp4 file
  • to store a video array to an .mp4 file

I tried implementing those as follows:

from ctypes import Union
from pathlib import Path
from typing import BinaryIO

import av
import numpy as np


def load(file_path, **kwargs) -> np.ndarray:
    frames = []
    with av.open(file_path, **kwargs) as container:
        for i, frame in enumerate(container.decode(video=0)):
            img = frame.to_image()
            frames.append(img)

    return np.moveaxis(np.stack(frames), -3, -2)


# following this approach: https://github.com/PyAV-Org/PyAV/issues/498
def save_to_file(
    np_tensor: np.ndarray,
    file_path: str,
    frame_rate: int = 30,
    codec: str = 'mpeg4',
) -> None:

    video_tensor = np.moveaxis(np.clip(np_tensor, 0, 255), -3, -2).astype('uint8')

    with av.open(file_path, mode='w') as container:
        if video_tensor.ndim == 3:
            video_tensor = np.expand_dims(video_tensor, axis=0)

        stream = container.add_stream(codec, rate=frame_rate)
        stream.width = video_tensor.shape[-2]
        stream.height = video_tensor.shape[-3]
        stream.pix_fmt = 'yuv420p'

        for vid in video_tensor:
            frame = av.VideoFrame.from_ndarray(vid, format="rgb24")
            frame.pts = None

            for packet in stream.encode(frame):
                container.mux(packet)

        for packet in stream.encode(None):
            container.mux(packet)


tmp_file = str(Path.cwd() / 'tmp.mp4')

video_tensor = np.array(
    [[
        [[1, 2, 3], [4, 5, 6]],
        [[7, 8, 9], [10, 11, 12]],
        [[13, 14, 15], [16, 17, 18]],
        [[19, 20, 21], [22, 23, 24]],
    ]]
)


save_to_file(np_tensor=video_tensor, file_path=tmp_file)

video_from_file = load(tmp_file)
assert video_tensor.shape == video_from_file.shape
print(f"tensor = {video_tensor}")
print(f"video_from_file = {video_from_file}")
assert np.allclose(video_tensor, video_from_file)

Expected behavior

I have an mp4 file, that I want to load to video_1. When storing the video_1 array to an mp4 file, and then load the video from that new file to a second array, video_2, I expect: np.allclose(video_1, video_2)

Actual behavior

I am getting an Assertion error:

tensor = [[[[ 1  2  3]
   [ 4  5  6]]

  [[ 7  8  9]
   [10 11 12]]

  [[13 14 15]
   [16 17 18]]

  [[19 20 21]
   [22 23 24]]]]
video_from_file = [[[[ 3  4  7]
   [ 3  4  7]]

  [[ 8  9 12]
   [ 8  9 12]]

  [[15 16 19]
   [15 16 19]]

  [[20 21 24]
   [20 21 24]]]]
Traceback (most recent call last):
  File "/Users/charlottegerhaher/Library/Application Support/JetBrains/PyCharm2022.2/scratches/scratch_26.py", line 68, in <module>
    assert np.allclose(video_tensor, video_from_file)
AssertionError

Traceback:

Traceback (most recent call last):
  File "/Users/charlottegerhaher/Library/Application Support/JetBrains/PyCharm2022.2/scratches/scratch_26.py", line 68, in <module>
    assert np.allclose(video_tensor, video_from_file)
AssertionError

Research

I have done the following:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions