napari / napari-animation

A napari plugin for making animations
https://napari.github.io/napari-animation/
Other
74 stars 27 forks source link

Include napari version information in output video metadata #167

Closed GenevieveBuckley closed 1 year ago

GenevieveBuckley commented 1 year ago

Description

Companion to PR https://github.com/napari/napari/pull/5494

This adds a digital watermark to the video files output by napari-animation. That means in the future it may be possible to scrape publications & supplementary data, eg: like this analysis done for matplotlib https://github.com/mrocklin/arxiv-matplotlib

Try it out!

Now, you can run the examples to create a video file:

python napari-animation/examples/animate2d.py

...and then look at the metadata embedded in the video file header with ffmpeg. This ffmpeg command writes the metadata to a text file:

!ffmpeg -i demo2d.mov -f ffmetadata FFMETADATAFILE.txt

And when you look at the output

cat FFMETADATAFILE.txt

...you see something like this (note the new "title" metadata field, which was not there before:

;FFMETADATA1
major_brand=qt  
minor_version=512
compatible_brands=qt  
title="napari version 0.4.17 https://napari.org/"
encoder=Lavf59.27.100

Actually, here is a simpler way to read the metadata from the video file:

    # Read metadata back in, and check for napari version information
    # We expect to see a metadata line in the metadata like this:
    # title="napari version 0.4.17 https://napari.org/"
    with open(output_video_filename, 'rb') as f:
        content = f.read()
    assert b"napari version" in content
    assert b"https://napari.org" in content

Additional details

I have stuffed the napari version information into the "title" metadata key, because that seems to be the most widely available. (.mp4 files do allow a "description" metadata field, but that is not supported by .avi, .mov, and possibly many other file formats).

codecov[bot] commented 1 year ago

Codecov Report

Merging #167 (3ad70f0) into main (d8bd609) will increase coverage by 0.90%. The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main     #167      +/-   ##
==========================================
+ Coverage   85.31%   86.22%   +0.90%     
==========================================
  Files          24       26       +2     
  Lines         926      987      +61     
==========================================
+ Hits          790      851      +61     
  Misses        136      136              
Impacted Files Coverage Δ
napari_animation/_tests/test_animation.py 100.00% <100.00%> (ø)
napari_animation/animation.py 87.25% <100.00%> (+0.38%) :arrow_up:

... and 3 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

GenevieveBuckley commented 1 year ago

Link to a notebook I used while I was figuring this out: https://gist.github.com/GenevieveBuckley/72e438539ab03c792d52040ccb9e8f02

The trick was, you need to SEPARATE the "-metadata" string from the "title=MyTitle" string in the output_params list that gets passed in to imageio_ffmpeg.

        output_params = ["-metadata", f'title="{description}"']

It will NOT work if you pass it all as one string, eg: output_params=["-metadata title=MyTitle"]

Plus, you just extend the idea if you want to pass in more metadata keys. The only problem is, not many metadata keys are supported by a wide variety of file formats.

output_params = [
    "-metadata", f'title="My Title"',
    "-metadata", f'description="Description goes here"',  # description metadata supported by .mp4, but not .mov, .avi, and possibly many other file formats
]
GenevieveBuckley commented 1 year ago

Thanks for the review!