Repository: just-work/fffw

Issue:
Concat audio fails validation
Samples count is not summed while concatenating audio.
Looks like concatenating video doesn't sum frames count.

Discussion:

Patch:
diff --git a/fffw/encoding/filters.py b/fffw/encoding/filters.py
index ff1baa2..1ef1505 100644
--- a/fffw/encoding/filters.py
+++ b/fffw/encoding/filters.py
@@ -3,7 +3,7 @@ from typing import Union, List, cast
 
 from fffw.graph import base
 from fffw.encoding import mixins
-from fffw.graph.meta import Meta, VideoMeta, TS, Scene, VIDEO, AUDIO
+from fffw.graph.meta import Meta, VideoMeta, TS, Scene, VIDEO, AUDIO, AudioMeta
 from fffw.graph.meta import StreamType, Device
 from fffw.wrapper.params import Params, param
 
@@ -330,16 +330,26 @@ class Concat(Filter):
         duration = TS(0)
         scenes = []
         streams: List[str] = []
+        samples = 0
+        sampling_rate = None
         for meta in metadata:
             duration += meta.duration
+            if isinstance(meta, AudioMeta):
+                samples += meta.samples
+                if sampling_rate is None:
+                    sampling_rate = meta.sampling_rate
+                else:
+                    assert sampling_rate == meta.sampling_rate
             scenes.extend(meta.scenes)
             for stream in meta.streams:
                 if not streams or streams[-1] != stream:
                     # Add all streams for each concatenated metadata and remove
                     # contiguous duplicates.
                     streams.append(stream)
-        return replace(metadata[0], duration=duration,
-                       scenes=scenes, streams=streams)
+        kwargs = dict(duration=duration, scenes=scenes, streams=streams)
+        if samples != 0:
+            kwargs['samples'] = samples
+        return replace(metadata[0], **kwargs)
 
 
 @dataclass


Test patch:
diff --git a/tests/test_graph.py b/tests/test_graph.py
index 5e82f6e..905464c 100644
--- a/tests/test_graph.py
+++ b/tests/test_graph.py
@@ -35,7 +35,10 @@ class FilterGraphTestCase(TestCase):
             par=1.0,
             duration=300.0,
         )
-        self.audio_metadata = audio_meta_data()
+        self.audio_metadata = audio_meta_data(
+            duration=200.0,
+            sampling_rate=48000,
+            samples_count=200*48000)
 
         self.source = inputs.Input(
             input_file='input.mp4',
@@ -239,6 +242,25 @@ class FilterGraphTestCase(TestCase):
         self.assertEqual(self.video_metadata.duration + vs.meta.duration,
                          vm.duration)
 
+    def test_concat_audio_metadata(self):
+        """
+        Concat filter sums samples count for audio streams.
+        """
+        audio_meta = audio_meta_data(duration=1000.0, sampling_rate=48000,
+                                     samples_count=48000 * 1000)
+        a = inputs.Stream(AUDIO, meta=audio_meta)
+        self.input_list.append(inputs.input_file('second.mp4', a))
+        concat = a | Concat(AUDIO)
+        self.source | concat
+
+        concat > self.output
+
+        am = cast(AudioMeta, self.output.codecs[-1].get_meta_data())
+        self.assertEqual(self.audio_metadata.duration + audio_meta.duration,
+                         am.duration)
+        self.assertEqual(self.audio_metadata.samples + audio_meta.samples,
+                         am.samples)
+
     def test_trim_metadata(self):
         """
         Trim filter sets start and changes stream duration.