Skip to content

Commit

Permalink
Merge pull request #61 from bbc/jamesba-segment-used-for-adding-grains
Browse files Browse the repository at this point in the history
v2.7.2: Restore some legacy behaviour with regard to adding grains to…
  • Loading branch information
jamesba authored Nov 11, 2019
2 parents b33fe76 + 19404bf commit 8c675fb
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Mediagrains Library Changelog

## 2.7.2
- Bugfix: Restore behaviour whereby grains can be added to a segment object during an active progressive encode

## 2.7.1
- Bugfix: Restore behaviour whereby `gsf.GSFEncoder.dump` calls `gsf.GSFEncoder.start_dump` and `gsf.GSFEncoder.end_dump`
(this matters if subclasses have overridden these methods)
Expand Down
33 changes: 27 additions & 6 deletions mediagrains/gsf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ def add_segment(self, id: Optional[UUID] = None, local_id: Optional[int] = None,
if self._active_dump:
raise GSFEncodeAddToActiveDump("Cannot add a new segment {} ({!s}) to an encoder that is currently dumping".format(local_id, id))

seg = GSFEncoderSegment(id, local_id, tags=tags)
seg = GSFEncoderSegment(id, local_id, tags=tags, parent=self)
self._segments[local_id] = seg
return seg

Expand Down Expand Up @@ -1471,7 +1471,7 @@ def add_segment(self, id: Optional[UUID] = None, local_id: Optional[int] = None,
if id is None:
id = uuid1()

seg = GSFEncoderSegment(id, local_id, tags=tags)
seg = GSFEncoderSegment(id, local_id, tags=tags, parent=self)
self._segments[local_id] = seg
return seg

Expand Down Expand Up @@ -1585,14 +1585,19 @@ def __eq__(self, other: object) -> bool:
class GSFEncoderSegment(object):
"""A class to represent a segment within a GSF file, used for constructing them."""

def __init__(self, id: UUID, local_id: int, tags: Iterable[Tuple[str, str]] = None):
def __init__(self,
id: UUID,
local_id: int,
tags: Iterable[Tuple[str, str]] = None,
parent: Optional[Union[GSFEncoder, OpenGSFEncoderBase]] = None):
self.id = id
self.local_id = local_id
self._write_count = 0
self._count_pos = -1
self._active_dump: bool = False
self._tags: List[GSFEncoderTag] = []
self._grains: List[GRAIN] = []
self._parent = parent

if tags is not None:
for tag in tags:
Expand All @@ -1601,6 +1606,14 @@ def __init__(self, id: UUID, local_id: int, tags: Iterable[Tuple[str, str]] = No
except (TypeError, IndexError):
raise GSFEncodeError("No idea how to turn {!r} into a tag".format(tag))

def _get_parent_open_encoder(self) -> Optional[OpenGSFEncoder]:
if isinstance(self._parent, OpenGSFEncoder):
return self._parent
elif isinstance(self._parent, GSFEncoder):
return self._parent._open_encoder
else:
return None

@property
def count(self) -> int:
return len(self._grains) + self._write_count
Expand Down Expand Up @@ -1833,10 +1846,18 @@ def add_tag(self, key: str, value: str):

def add_grain(self, grain: GRAIN):
"""Add a grain to the segment, which should be a Grain object"""
self._grains.append(grain)
parent = self._get_parent_open_encoder()
if parent is not None and parent._active_dump:
parent.add_grain(grain, segment_id=self.id, segment_local_id=self.local_id)
else:
self._grains.append(grain)

def add_grains(self, grains: Iterable[GRAIN]):
"""Add several grains to the segment, the parameter should be an
iterable of grain objects"""
for grain in grains:
self.add_grain(grain)
parent = self._get_parent_open_encoder()
if parent is not None and parent._active_dump:
parent.add_grains(grains, segment_id=self.id, segment_local_id=self.local_id)
else:
for grain in grains:
self.add_grain(grain)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
]

setup(name="mediagrains",
version="2.7.1",
version="2.7.2",
python_requires='>=3.6.0',
description="Simple utility for grain-based media",
url='https://github.com/bbc/rd-apmm-python-lib-mediagrains',
Expand Down
41 changes: 41 additions & 0 deletions tests/test_gsf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,47 @@ def test_dump_progressively__deprecated(self):
self.assertEqual(len(segments2[1]), 2)
self.assertEqual(len(segments3[1]), 2)

@suppress_deprecation_warnings
def test_dump_progressively_with_segments__deprecated(self):
src_id = UUID('e14e9d58-1567-11e8-8dd3-831a068eb034')
flow_id = UUID('ee1eed58-1567-11e8-a971-3b901a2dd8ab')
grain0 = VideoGrain(src_id, flow_id, cog_frame_format=CogFrameFormat.S16_422_10BIT, width=1920, height=1080)
grain1 = VideoGrain(src_id, flow_id, cog_frame_format=CogFrameFormat.S16_422_10BIT, width=1920, height=1080)

uuids = [UUID('7920b394-1565-11e8-86e0-8b42d4647ba8'),
UUID('80af875c-1565-11e8-8f44-87ef081b48cd')]
created = datetime(1983, 3, 29, 15, 15)

file = BytesIO()
with mock.patch('mediagrains.gsf.datetime', side_effect=datetime, now=mock.MagicMock(return_value=created)):
with mock.patch('mediagrains.gsf.uuid1', side_effect=uuids):
enc = GSFEncoder(file)
seg = enc.add_segment()
self.assertEqual(len(file.getvalue()), 0)
enc.start_dump()
dump0 = file.getvalue()
(head0, segments0) = loads(dump0)
seg.add_grain(grain0)
dump1 = file.getvalue()
(head1, segments1) = loads(dump1)
seg.add_grain(grain1, segment_local_id=1)
dump2 = file.getvalue()
(head2, segments2) = loads(dump2)
enc.end_dump()
dump3 = file.getvalue()
(head3, segments3) = loads(dump3)

self.assertEqual(head0['segments'][0]['count'], -1)
self.assertEqual(head1['segments'][0]['count'], -1)
self.assertEqual(head2['segments'][0]['count'], -1)
self.assertEqual(head3['segments'][0]['count'], 2)

if 1 in segments0:
self.assertEqual(len(segments0[1]), 0)
self.assertEqual(len(segments1[1]), 1)
self.assertEqual(len(segments2[1]), 2)
self.assertEqual(len(segments3[1]), 2)

def test_dump_progressively(self):
src_id = UUID('e14e9d58-1567-11e8-8dd3-831a068eb034')
flow_id = UUID('ee1eed58-1567-11e8-a971-3b901a2dd8ab')
Expand Down

0 comments on commit 8c675fb

Please sign in to comment.