bbc/rd-apmm-python-lib-mediagrains

Name: rd-apmm-python-lib-mediagrains

Owner: BBC

Description: A python library for handling grain-based media

Created: 2018-02-02 13:56:08.0

Updated: 2018-05-21 10:22:59.0

Pushed: 2018-05-04 12:34:34.0

Homepage: null

Size: 253

Language: Python

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

rd-apmm-python-lib-mediagrains

A python library for handling grain-based media in a python-native style. Please read the pydoc documentation for more details.

Provides constructor functions for various types of grains and classes that nicely wrap those grains, as well as a full serialisation and deserialisation library for GSF format.

Installing with Python and make

To run the installer run

make install

to create a redistributable source tarball call

make source

Running tests

To run the tests for python2 run

make test2

to run the tests for python3 run

make test3

to run both run

make test

All tests are run inside a virtual environment so as to avoid polluting the global python environment.

prerequisites

The nmoscommon library used to provide the Timestamp class is needed during testing. This library is available here:

< git+https: //github.com/jamesba/nmos-common/@python3 >

to install this package that one must be installed, to run the tests it must be available in a repository that pip will look at during package instalation (if you don't have such a repo you can set one up quickly using devpi).

Examples

As an example of using this in your own code the following is a simple program to load the contents of a GSF file and print the timestamp of each grain.

from mediagrains.gsf import load
f = open('examples/video.gsf', "rb")
(head, segments) = load(f)
print('\n'.join(str(grain.origin_timestamp) for grain in segments[1]))
102800:0
102800:20000000
102800:40000000
102800:60000000
102800:80000000
102800:100000000
102800:120000000
102800:140000000
102800:160000000
102800:180000000

Alternatively to create a new video grain in 10-bit planar YUV 4:2:0 and fill it with colour-bars:

from mediagrains import VideoGrain
from uuid import uuid1
from mediagrains.cogenum import CogFrameFormat, CogFrameLayout
src_id = uuid1()
flow_id = uuid1()
grain = VideoGrain(src_id, flow_id, cog_frame_format=CogFrameFormat.S16_422_10BIT, width=1920, height=1080)
colours = [
     (0x3FF, 0x000, 0x3FF),
     (0x3FF, 0x3FF, 0x000),
     (0x3FF, 0x000, 0x000),
     (0x3FF, 0x3FF, 0x3FF),
     (0x3FF, 0x200, 0x3FF),
     (0x3FF, 0x3FF, 0x200) ]
x_offset = [0, 0, 0]
for colour in colours:
    i = 0
    for c in grain.components:
            for x in range(0,c.width//len(colours)):
                    for y in range(0,c.height):
                            grain.data[c.offset + y*c.stride + (x_offset[i] + x)*2 + 0] = colour[i] & 0xFF
                            grain.data[c.offset + y*c.stride + (x_offset[i] + x)*2 + 1] = colour[i] >> 8
            x_offset[i] += c.width//len(colours)
            i += 1

The object grain can then be freely used for whatever video processing is desired, or it can be serialised into a GSF file as follows:

from mediagrains.gsf import dump
f = open('dummyfile.gsf', 'wb')
dump(f, [grain])
f.close()

The encoding module also supports a “progressive” mode where an encoder object is created and a dump started, then grains can be added and will be written to the output file as they are added.

from uuid import uuid1
from mediagrains import Grain
from mediagrains.gsf import GSFEncoder
src_id = uuid1()
flow_id = uuid1()
f = open('dummyfile.gsf', 'wb')
enc = GSFEncoder(f)
seg = enc.add_segment()  # This must be done before the call to start_dump
enc.start_dump()  # This writes the file header and starts the export
seg.add_grain(Grain(src_id, flow_id))  # Adds a grain and writes it to the file
seg.add_grain(Grain(src_id, flow_id))  # Adds a grain and writes it to the file
seg.add_grain(Grain(src_id, flow_id))  # Adds a grain and writes it to the file
enc.end_dump()  # This ends the export and finishes off the file
f.close()

If the underlying file is seekable then the end_dump call will upade all segment metadata to list the correct grain count, otherwise the counts will be left at -1.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.