Repository: cvat-ai/cvat
Pull request: Make function get_progress be compatible with more video format
* Add function _get_duration with VideoReader
* Update function get_progress of VideoReader

<!---
Copyright (C) 2020-2021 Intel Corporation

SPDX-License-Identifier: MIT
-->

<!-- Raised an issue to propose your change (https://github.com/opencv/cvat/issues).
It will help avoiding duplication of efforts from multiple independent contributors.
Discuss your ideas with maintainers to be sure that changes will be approved and merged.
Read the [CONTRIBUTION](https://github.com/opencv/cvat/blob/develop/CONTRIBUTING.md)
guide. -->

<!-- Provide a general summary of your changes in the Title above -->

### Motivation and context
<!-- Why is this change required? What problem does it solve? If it fixes an open
issue, please link to the issue here. Describe your changes in detail, add
screenshots. -->

### How has this been tested?
<!-- Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc. -->

### Checklist
<!-- Go over all the following points, and put an `x` in all the boxes that apply.
If an item isn't applicable by a reason then ~~explicitly strikethrough~~ the whole
line. If you don't do that github will show incorrect process for the pull request.
If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] I submit my changes into the `develop` branch
- [ ] I have added description of my changes into [CHANGELOG](https://github.com/opencv/cvat/blob/develop/CHANGELOG.md) file
- [ ] I have updated the [documentation](
  https://github.com/opencv/cvat/blob/develop/README.md#documentation) accordingly
- [ ] I have added tests to cover my changes
- [x] I have linked related issues ([read github docs](
  https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))
- [x] I have increased versions of npm packages if it is necessary ([cvat-canvas](https://github.com/opencv/cvat/tree/develop/cvat-canvas#versioning),
[cvat-core](https://github.com/opencv/cvat/tree/develop/cvat-core#versioning), [cvat-data](https://github.com/opencv/cvat/tree/develop/cvat-data#versioning) and [cvat-ui](https://github.com/opencv/cvat/tree/develop/cvat-ui#versioning))

### License

- [ ] I submit _my code changes_ under the same [MIT License](
  https://github.com/opencv/cvat/blob/develop/LICENSE) that covers the project.
  Feel free to contact the maintainers if that's a concern.
- [ ] I have updated the license header for each file (see an example below)

```python
# Copyright (C) 2021 Intel Corporation
#
# SPDX-License-Identifier: MIT
```


Problem statement:
get_prpgress function of VideoReader can compatible with more video format
<!---
Copyright (C) 2020 Intel Corporation

SPDX-License-Identifier: MIT
-->

### My actions before raising this issue
while extract from video with typical format, like mkv, it can't show precise progress. Like shown in the code:
```python
    def get_progress(self, pos):
        container = self._get_av_container()
        # Not for all containers return real value
        stream = container.streams.video[0]
        return pos / stream.duration if stream.duration else None
```
VideoStream object may not have a real duration value.

<!--- Provide a general summary of the issue in the Title above -->

### Expected Behaviour
<!--- If you're describing a bug, tell us what should happen. If you're
suggesting a change/improvement, tell us how it should work -->
But we can find duration information from metadata of VideoStream object, then we can calculate precise progress instead of showing "Images are being compressed |/-\\"

Hints from issue discussion:
@Thatwho Hi, thanks for the suggestion, would you like to prepare a PR for this?
> @Thatwho Hi, thanks for the suggestion, would you like to prepare a PR for this?

Of course! I had made a PR which is #3381. Please let me know the PR has any error.

Commit message: Make function get_progress be compatible with more video format
* Add function _get_duration with VideoReader
* Update function get_progress of VideoReader

Patch to review:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98964a61b1af..a4a1b4063c1b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Duplication of the cuboids when redraw them (<https://github.com/openvinotoolkit/cvat/pull/3308>)
 - Some code issues in Deep Extreme Cut handler code (<https://github.com/openvinotoolkit/cvat/pull/3325>)
 - UI fails when inactive user is assigneed to a task/job (<https://github.com/openvinotoolkit/cvat/pull/3343>)
+- Can't calculat precise progress of image extraction and compression when operating video with particular format (https://github.com/openvinotoolkit/cvat/pull/3381)
 
 ### Security
 
diff --git a/cvat/apps/engine/media_extractors.py b/cvat/apps/engine/media_extractors.py
index d3184e0968d7..109fd7bad861 100644
--- a/cvat/apps/engine/media_extractors.py
+++ b/cvat/apps/engine/media_extractors.py
@@ -325,16 +325,30 @@ def __iter__(self):
         return self._decode(container)
 
     def get_progress(self, pos):
-        container = self._get_av_container()
-        # Not for all containers return real value
-        stream = container.streams.video[0]
-        return pos / stream.duration if stream.duration else None
+        duration = self._get_duration()
+        return pos / duration if duration else None
 
     def _get_av_container(self):
         if isinstance(self._source_path[0], io.BytesIO):
             self._source_path[0].seek(0) # required for re-reading
         return av.open(self._source_path[0])
 
+    def _get_duration(self):
+        container = self._get_av_container()
+        stream = container.streams.video[0]
+        duration = None
+        if stream.duration:
+            duration = stream.duration
+        else:
+            # may have a DURATION in format like "01:16:45.935000000"
+            duration_str = stream.metadata.get("DURATION", None)
+            tb_denominator = stream.time_base.denominator
+            if duration_str and tb_denominator:
+                _hour, _min, _sec = duration_str.split(':')
+                duration_sec = 60*60*float(_hour) + 60*float(_min) + float(_sec)
+                duration = duration_sec * tb_denominator
+        return duration
+
     def get_preview(self):
         container = self._get_av_container()
         stream = container.streams.video[0]


Code review comments:
diff_hunk: @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Duplication of the cuboids when redraw them (<https://github.com/openvinotoolkit/cvat/pull/3308>)
 - Some code issues in Deep Extreme Cut handler code (<https://github.com/openvinotoolkit/cvat/pull/3325>)
 - UI fails when inactive user is assigneed to a task/job (<https://github.com/openvinotoolkit/cvat/pull/3343>)
+- Can't calculat precise progress of image extraction and compression when operating video with particular format (https://github.com/openvinotoolkit/cvat/pull/3381)
path: CHANGELOG.md
text: @user1:
```suggestion
- Calculate precise progress of decoding a video file (https://github.com/openvinotoolkit/cvat/pull/3381)
```