AcademySoftwareFoundation / AcademySoftwareFoundation/OpenTimelineIO
dealing with zero rate clips
- Dominant language
- C++
- Stars
- 2k
- Forks
- 351
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 1
Description
Problem:
It is possible for Heiro to write an xml that has clips with a timebase of zero.
This causes the opentime.RationalTime object to have a rate of zero, which means
that the otioview application will crash with a divide by zero error.
It also means that we are allowing RationalTime to store value*(1/0) which is,
in my opinion, a nonsensical value. One thing I don't know is if a value of zero
in timebase is ever okay, or is used to signify a something else all together.
I've included a sample file that will trigger the crash and the resulting
stacktrace at the end of this post. The sample file is a trimmed down
version of a file with the offending data that I encountered in a production
published timeline at our studio. Once the bug is fixed and/or the data is
fixed this Sample File will successfully load up in otioview.
Possible Solutions:
01. Have an error message that says something to the effect of:
"file {file} sequence {seq} track {track} clip {clip} has a frame rate of zero"
" - please correct this in the source file."
I'm not yet sure where the best place to put that in the code would be.
02. Don't allow a RationalTime object to be initialized with a rate of zero
and throw an error when it is attempted,
-OR- replace any rate of 0 with a rate of 1 and emit an warning message.
03. Add a try/catch clause for a rate of zero to RationalTime.value_rescaled_to()
since we already catch type errors there,
-OR- replace any rate of 0 with a rate of 1 and emit an warning message.
04. Add mypy type annotations and/or contract decorators to prevent
this class of error from creeping back in unnoticed.
05. Submit a bug report to hiero, asking why zero frame rates are allowed.
Naturally, this is something I will do, but I list it here so we all know
that I am doing it.
Instructions to reproduce error:
01. on a linux machine, run this command as root: pip install OpenTimelineIO
02. safe the Sample File bellow as ~/hiero_bad_fps.xml
03. from the command line run: /usr/bin/otioview ~/hiero_bad_fps.xml
04. you should see the traceback bellow.
05. you can replace the value 30 with 0 for any timebase in this example
and get the same error
Sample File:
FALSE
30
FALSE
30
0.0
5579.0
0
5579
file://localhost/bad_audio.wav
5579
FALSE
0
0
Sample File End.
SITE_PACK = /usr/lib64/python2.7/site-packages
Traceback (most recent call last):
/usr/bin/otioview::10
sys.exit(main())
SITE_PACK/opentimelineview/console.py:main:280
window.load(args.input)
SITE_PACK/opentimelineview/console.py:load:198
**self.adapter_argument_map
SITE_PACK/opentimelineio/adapters/__init__.py:read_from_file:144
**adapter_argument_map
SITE_PACK/opentimelineio/adapters/adapter.py:read_from_file:130
**adapter_argument_map
SITE_PACK/opentimelineio/plugins/python_plugin.py:_execute_function:128
return (getattr(self.module(), func_name)(**kwargs))
SITE_PACK/opentimelineio/adapters/fcp_xml.py:read_from_string:1905
sequences = parser.top_level_sequences()
SITE_PACK/opentimelineio/adapters/fcp_xml.py:top_level_sequences:641
return [self.timeline_for_sequence(s, context) for s in sequence_iter]
SITE_PACK/opentimelineio/adapters/fcp_xml.py:timeline_for_sequence:683
tracks = self.stack_for_element(media_element, local_context)
SITE_PACK/opentimelineio/adapters/fcp_xml.py:stack_for_element:734
track_element, track_kind, local_context
SITE_PACK/opentimelineio/adapters/fcp_xml.py:track_for_element:797
local_context,
SITE_PACK/opentimelineio/adapters/fcp_xml.py:item_and_timing_for_element:970
item_element, item_range, start_offset, context
SITE_PACK/opentimelineio/adapters/fcp_xml.py:clip_for_element:1020
file_element, local_context
SITE_PACK/opentimelineio/adapters/fcp_xml.py:media_reference_for_file_element:849
start_time = start_time.rescaled_to(media_ref_rate)
SITE_PACK/opentimelineio/opentime.py:rescaled_to:101
self.value_rescaled_to(new_rate),
SITE_PACK/opentimelineio/opentime.py:value_rescaled_to:118
return float(self.value) * float(new_rate) / float(self.rate)
ZeroDivisionError: float division by zero
Contributor guide
Research direction
Start with the supplied zero-timebase XML and reproduce the crash using otioview. Read opentimelineio/adapters/fcp_xml.py around media_reference_for_file_element and opentimelineio/opentime.py around value_rescaled_to; determine the intended handling for a zero rate. Done means the sample file no longer crashes with a divide-by-zero error and the behavior is covered appropriately.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100