emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/subed d5e48886f4 1/2: 1.2.14: Bugfix: handle waveform for


From: ELPA Syncer
Subject: [nongnu] elpa/subed d5e48886f4 1/2: 1.2.14: Bugfix: handle waveform for last cue
Date: Wed, 10 Jul 2024 22:01:37 -0400 (EDT)

branch: elpa/subed
commit d5e48886f4472a644c1c406dd8994b357abd15d8
Author: Sacha Chua <sacha@sachachua.com>
Commit: Sacha Chua <sacha@sachachua.com>

    1.2.14: Bugfix: handle waveform for last cue
    
    subed-waveform should now handle the case where
    the stop time + subed-waveform-preview-msecs-after
    might extend past the end of the file.
    
    * subed/subed-waveform.el (subed-waveform-ffprobe-executable): New.
    (subed-waveform-file-duration-ms-cache): New.
    (subed-waveform-ffprobe-duration-ms): New,
    calculates duration.
    (subed-waveform-file-duration-ms): New function
    for caching the duration.
    (subed-waveform-clear-file-duration-ms-cache): New.
    (subed-mpv): Add advice around
    subed-mpv-play-from-file for now;
    ideally change this to a hook later on.
    (subed-waveform--image-parameters): Move to a separate
    function for easier testing.
    (subed-waveform--make-overlay): Do the
    calculations in subed-waveform--image-parameters.
    (subed-waveform--update-bars): Use the actual stop
    time if needed.
    * tests/test-subed-waveform.el: New.
    * Set lexical-binding: t in tests/* files
    
    Thanks to rodrigomorales1 and rndusr for bug
    reports and pull requests!
    
    Related:
    - https://github.com/sachac/subed/issues/68
    - https://github.com/sachac/subed/pull/75
    - https://github.com/sachac/subed/issues/74
---
 AUTHORS.org                          |   5 +-
 NEWS.org                             |   9 ++
 subed/subed-waveform.el              | 197 +++++++++++++++++++++++++++----
 subed/subed-waveform.el.license      |   2 +-
 subed/subed.el                       |   2 +-
 tests/test-subed-mpv.el              |   2 +-
 tests/test-subed-srt.el              |   2 +-
 tests/test-subed-tsv.el              |   2 +-
 tests/test-subed-waveform.el         | 217 +++++++++++++++++++++++++++++++++++
 tests/test-subed-waveform.el.license |   3 +
 10 files changed, 412 insertions(+), 29 deletions(-)

diff --git a/AUTHORS.org b/AUTHORS.org
index 443709a4e2..55ec1e20f4 100644
--- a/AUTHORS.org
+++ b/AUTHORS.org
@@ -1,5 +1,5 @@
 #+BEGIN_COMMENT
-SPDX-FileCopyrightText: 2021 The subed Authors
+SPDX-FileCopyrightText: 2021-2024 The subed Authors
 
 SPDX-License-Identifier: CC0-1.0
 #+END_COMMENT
@@ -12,4 +12,7 @@ Please note this shouldn't be taken as a list of copyright 
holders,
 nor is it necessarily complete.
 
 - Random User <rndusr@posteo.de> (original creator)
+- Sacha Chua <sacha@sachachua.com>
 - Sebastian 'seabass' Crane <seabass-labrax@gmx.com>
+- Marcin Borkowski
+- Rodrigo Morales
diff --git a/NEWS.org b/NEWS.org
index fd434de8bc..78c0e30cef 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -1,6 +1,15 @@
 #+OPTIONS: toc:nil
 
 * subed news
+** Version 1.2.14 - 2024-07-05 - Sacha Chua
+
+- Bugfix: subed-waveform should now handle the
+  case where the stop time +
+  subed-waveform-preview-msecs-after might extend
+  past the end of the file.
+
+  Thanks to rodrigomorales1 and rnduser for the bug reports and pull requests!
+
 ** Version 1.2.13 - 2024-07-05 - Sacha Chua
 
 - Bugfix: Fix the requires in subed-waveform to load subed-common.
diff --git a/subed/subed-waveform.el b/subed/subed-waveform.el
index 8b78810267..66fce8b7a5 100644
--- a/subed/subed-waveform.el
+++ b/subed/subed-waveform.el
@@ -1,6 +1,6 @@
 ;;; subed-waveform.el --- display waveforms in subed buffers  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2023 Sacha Chua, Marcin Borkowski
+;; Copyright (C) 2023-2024 Sacha Chua, Marcin Borkowski, Rodrigo Morales
 
 ;; Author: Sacha Chua <sacha@sachachua.com>, Marcin Borkowski <mbork@mbork.pl>
 ;; Keywords: multimedia
@@ -140,6 +140,11 @@ SVG parameters of the displayed bars.  Every bar must have 
a unique
     :value-type (plist :key-type symbol :value-type string))
   :group 'subed-waveform)
 
+(defcustom subed-waveform-ffprobe-executable "ffprobe"
+  "Path to the FFprobe executable used for measuring file duration."
+  :type 'file
+  :group 'subed-waveform)
+
 (defcustom subed-waveform-preview-msecs-before 2000
   "Prelude in milliseconds displaying subtitle waveform."
   :type 'integer
@@ -244,6 +249,123 @@ WIDTH and HEIGHT are given in pixels."
            width height)
    
"[bg][fg]overlay=format=auto,drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=1:color=#9cf42f"))
 
+(defvar-local subed-waveform-file-duration-ms-cache nil "If non-nil, duration 
of current file in milliseconds.")
+
+(defun subed-waveform-convert-ffprobe-tags-duration-to-ms (duration)
+  "Return milliseconds as an integer for DURATION.
+
+DURATION must be a string of the format HH:MM:SS.MMMM.
+
+Example:
+
+00:00:03.003000000 -> 3003
+00:00:03.00370000 -> 3004"
+  (unless (string-match 
"\\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\)\\.\\([0-9]+\\)" 
duration)
+    (error "The duration is not well formatted."))
+  (let ((hour (match-string 1 duration))
+        (minute (match-string 2 duration))
+        (seconds (match-string 3 duration))
+        (milliseconds (match-string 4 duration)))
+    (+
+     (* (string-to-number hour) 3600000)
+     (* (string-to-number minute) 60000)
+     (* (string-to-number seconds) 1000)
+     (* (string-to-number (concat "0." milliseconds)) 1000))))
+
+(defun subed-waveform-ffprobe-duration-ms (filename)
+  "Use ffprobe to get duration of audio stream in milliseconds of FILENAME."
+  (let ((json
+         (json-read-from-string
+          (with-temp-buffer
+            (call-process
+             subed-waveform-ffprobe-executable nil t nil
+             "-v" "error"
+             "-print_format" "json"
+             "-show_streams"
+             "-show_format"
+             filename)
+            (buffer-string)))))
+    ;; Check that the file has at least one audio stream.
+    (when (eq (seq-find
+               (lambda (stream)
+                 (equal (alist-get 'codec_type stream) "audio"))
+               (alist-get 'streams json))
+              0)
+      (error "The provided file doesn't have an audio stream."))
+    (cond
+     ;; If the file has one stream and it is an audio stream, we can
+     ;; get the duration from format=duration
+     ;;
+     ;; nb_streams equals the number of streams in the media file.
+     ((and (eq (alist-get 'nb_streams (alist-get 'format json)) 1)
+           (equal (alist-get
+                   'codec_type
+                   (seq-first (alist-get 'streams json)))
+                  "audio"))
+      (* 1000 (string-to-number
+               (alist-get 'duration (alist-get 'format json)))))
+     ;; If the file has more than one stream and only one audio
+     ;; stream, return the duration of the audio stream.
+     ((and (> (alist-get 'nb_streams (alist-get 'format json)) 1)
+           (eq (length (seq-filter
+                        (lambda (stream)
+                          (equal (alist-get 'codec_type stream) "audio"))
+                        (alist-get 'streams json)))
+               1))
+      (cond
+       ((or
+         (string-match "\\.mkv\\'" filename)
+         (string-match "\\.webm\\'" filename))
+        (subed-waveform-convert-ffprobe-tags-duration-to-ms
+         (alist-get
+          'DURATION
+          (alist-get
+           'tags
+           (seq-find
+            (lambda (stream)
+              (equal (alist-get 'codec_type stream) "audio"))
+            (alist-get 'streams json))))))
+       (t
+        (* 1000
+           (string-to-number
+            (alist-get
+             'duration
+             (seq-find
+              (lambda (stream)
+                (equal (alist-get 'codec_type stream) "audio"))
+              (alist-get 'streams json))))))))
+     ;; TODO: Some media files might have multiple audio streams
+     ;; (e.g. multiple languages). When the media file has multiple
+     ;; audio streams, prompt the user for the audio stream. The audio
+     ;; stream selected by the user must be stored in a buffer-local
+     ;; variable so that ffmpeg knows the audio stream from which the
+     ;; waveforms are created.
+     )))
+
+(defun subed-waveform-file-duration-ms (&optional filename)
+  "Return the duration of FILENAME in milliseconds."
+  (cond
+   (subed-waveform-file-duration-ms-cache
+    (when (> subed-waveform-file-duration-ms-cache 0)
+      subed-waveform-file-duration-ms-cache))
+   (subed-waveform-ffprobe-executable
+    (setq subed-waveform-file-duration-ms-cache
+          (subed-waveform-ffprobe-duration-ms
+           (or filename (subed-media-file))))
+    (if (> subed-waveform-file-duration-ms-cache 0)
+        subed-waveform-file-duration-ms-cache
+      ;; mark as invalid
+      (setq subed-waveform-file-duration-ms-cache -1)
+      nil))))
+
+(defun subed-waveform-clear-file-duration-ms-cache (&rest _)
+  "Clear `subed-waveform-file-duration-ms-cache'."
+  (setq subed-waveform-file-duration-ms-cache nil))
+
+;; This should eventually be replaced with a hook.
+(with-eval-after-load 'subed-mpv
+  (advice-add 'subed-mpv-play-from-file :after 
'subed-waveform-clear-file-duration-ms-cache))
+
 (defun subed-waveform--from-file (filename from to width height)
   "Returns a string representing the image data in PNG format.
 FILENAME is the input file, FROM and TO are time positions, WIDTH
@@ -284,34 +406,60 @@ and HEIGHT are dimensions in pixels."
   (when pos
     (format "%.2f%%" (/ (* 100.0 (- pos start)) (- stop start)))))
 
+(defun subed-waveform--image-parameters (&optional width height)
+  "Return a plist of media-file, start, stop, width, height.
+Use WIDTH and HEIGHT if specified."
+  (let* ((duration (subed-waveform-file-duration-ms (subed-media-file)))
+         (start (floor (max 0 (- (subed-subtitle-msecs-start) 
subed-waveform-preview-msecs-before))))
+         (stop
+          (min
+           (floor (+ (subed-subtitle-msecs-stop) 
subed-waveform-preview-msecs-after))
+           (or duration most-positive-fixnum)))
+         (width-ratio
+          (/
+           (* 100.0 (- stop start))
+           (- (+ (subed-subtitle-msecs-stop) 
subed-waveform-preview-msecs-after) start)))
+         (width (or width (/ (* width-ratio (string-pixel-width (make-string 
fill-column ?*)))
+                             (face-attribute 'default :height))))
+         (height (or height (save-excursion
+                              ;; don't count the current waveform towards the
+                              ;; line height
+                              (forward-line -1)
+                              (* 2 (line-pixel-height))))))
+    (list
+     :file
+     (or (subed-media-file)
+         (error "No media file found"))
+     :start
+     start
+     :stop
+     stop
+     :width
+     width
+     :height
+     height)))
+
 (defun subed-waveform--make-overlay (&optional width height)
   "Make an overlay at point for the current subtitle."
   (let* ((overlay (make-overlay (point) (point)))
-         (start (floor (max 0 (- (subed-subtitle-msecs-start) 
subed-waveform-preview-msecs-before))))
-         (stop (floor (+ (subed-subtitle-msecs-stop) 
subed-waveform-preview-msecs-after)))
-         (width (/ (* 100.0 (string-pixel-width (make-string fill-column ?*)))
-                   (face-attribute 'default :height)))
-         (height (save-excursion
-                   ;; don't count the current waveform towards the
-                   ;; line height
-                   (forward-line -1)
-                   (* 2 (line-pixel-height))))
+         (params (subed-waveform--image-parameters width height))
          (image (subed-waveform--from-file
-                 (or (subed-media-file)
-                     (error "No media file found"))
-                 (subed-waveform--msecs-to-ffmpeg start)
-                 (subed-waveform--msecs-to-ffmpeg stop)
-                 width
-                 height))
-         (svg (svg-create width height)))
+                 (plist-get params :file)
+                 (subed-waveform--msecs-to-ffmpeg (plist-get params :start))
+                 (subed-waveform--msecs-to-ffmpeg (plist-get params :stop))
+                 (plist-get params :width)
+                 (plist-get params :height)))
+         (svg (svg-create
+               (plist-get params :width)
+               (plist-get params :height))))
     (svg-embed svg image "image/png" t
                :x 0 :y 0
                :width "100%" :height "100%"
                :preserveAspectRatio "none")
     (overlay-put overlay 'subed-waveform t)
     (overlay-put overlay 'after-string "\n")
-    (overlay-put overlay 'waveform-start start)
-    (overlay-put overlay 'waveform-stop stop)
+    (overlay-put overlay 'waveform-start (plist-get params :start))
+    (overlay-put overlay 'waveform-stop (plist-get params :stop))
     (overlay-put overlay 'before-string
                  (propertize
                   " "
@@ -319,9 +467,11 @@ and HEIGHT are dimensions in pixels."
                   'svg svg
                   'pointer 'arrow
                   'keymap subed-waveform-svg-map
-                  'waveform-start start
-                  'waveform-stop stop
-                  'waveform-pixels-per-second (/ width (* 0.001 (- stop 
start)))))
+                  'waveform-start (plist-get params :start)
+                  'waveform-stop (plist-get params :stop)
+                  'waveform-pixels-per-second (/ (plist-get params :width)
+                                                 (* 0.001 (- (plist-get params 
:stop)
+                                                             (plist-get params 
:start))))))
     (unless subed-waveform-show-all
       (setq subed-waveform--overlay overlay)
       (setq subed-waveform--svg svg))
@@ -365,7 +515,8 @@ If POSITION is nil, remove the bar."
   "Update the bars in OVERLAY."
   (setq overlay (or overlay (subed-waveform--get-current-overlay)))
   (let* ((start (subed-subtitle-msecs-start))
-         (stop (subed-subtitle-msecs-stop))
+         (stop (min (subed-subtitle-msecs-stop)
+                    (or (subed-waveform-file-duration-ms) 
most-positive-fixnum)))
          (start-pos (subed-waveform--position-to-percent
                      start
                      (overlay-get overlay 'waveform-start)
diff --git a/subed/subed-waveform.el.license b/subed/subed-waveform.el.license
index 8de80387df..d930de3cb7 100644
--- a/subed/subed-waveform.el.license
+++ b/subed/subed-waveform.el.license
@@ -1,3 +1,3 @@
-;;;; SPDX-FileCopyrightText: 2023 Sacha Chua, Marcin Borkowski
+;;;; SPDX-FileCopyrightText: 2023, 2024 Sacha Chua, Marcin Borkowski, Rodrigo 
Morales
 ;;;;
 ;;;; SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/subed/subed.el b/subed/subed.el
index 284bc24053..c16522fa8b 100644
--- a/subed/subed.el
+++ b/subed/subed.el
@@ -1,6 +1,6 @@
 ;;; subed.el --- A major mode for editing subtitles  -*- lexical-binding: t; 
-*-
 
-;; Version: 1.2.13
+;; Version: 1.2.14
 ;; Maintainer: Sacha Chua <sacha@sachachua.com>
 ;; Author: Random User
 ;; Keywords: convenience, files, hypermedia, multimedia
diff --git a/tests/test-subed-mpv.el b/tests/test-subed-mpv.el
index 3c292a28b8..bf04fd5c73 100644
--- a/tests/test-subed-mpv.el
+++ b/tests/test-subed-mpv.el
@@ -1,4 +1,4 @@
-;; -*- eval: (buttercup-minor-mode) -*-
+;; -*- lexical-binding: t; eval: (buttercup-minor-mode) -*-
 
 (load-file "./tests/undercover-init.el")
 (require 'subed-mpv)
diff --git a/tests/test-subed-srt.el b/tests/test-subed-srt.el
index 564db390a7..717901c62f 100644
--- a/tests/test-subed-srt.el
+++ b/tests/test-subed-srt.el
@@ -1,4 +1,4 @@
-;; -*- eval: (buttercup-minor-mode) -*-
+;; -*- lexical-binding: t; eval: (buttercup-minor-mode) -*-
 
 (load-file "./tests/undercover-init.el")
 (require 'subed-srt)
diff --git a/tests/test-subed-tsv.el b/tests/test-subed-tsv.el
index 50c99d28f5..24adfb9f00 100644
--- a/tests/test-subed-tsv.el
+++ b/tests/test-subed-tsv.el
@@ -1,4 +1,4 @@
-;; -*- eval: (buttercup-minor-mode) -*-
+;; -*- lexical-binding: t; eval: (buttercup-minor-mode) -*-
 
 (add-to-list 'load-path "./subed")
 (require 'subed)
diff --git a/tests/test-subed-waveform.el b/tests/test-subed-waveform.el
new file mode 100644
index 0000000000..5948532e21
--- /dev/null
+++ b/tests/test-subed-waveform.el
@@ -0,0 +1,217 @@
+;; -*- eval: (buttercup-minor-mode); lexical-binding: t -*-
+
+(require 'subed-waveform)
+
+(cl-defun create-sample-media-file-1-audio-stream (&key
+                                                   path
+                                                   duration-audio-stream)
+  "Create a sample media file with one audio stream
+
+PATH is the absolute path for the output file. It must be a
+string.
+
+DURATION is the number of seconds for the media file. It must be
+a string."
+  (call-process
+   ;; The ffmpeg command shown below can create files with the
+   ;; extensions shown below (tested using ffmpeg version
+   ;; 4.4.2-0ubuntu0.22.04.1)
+   ;; + audio extensions: wav ogg mp3 opus m4a
+   ;; + video extensions: mkv mp4 webm avi ts ogv"
+   "ffmpeg"
+   nil
+   nil
+   nil
+   "-v" "error"
+   "-y"
+   ;; We use lavfi to create the audio stream
+   "-f" "lavfi" "-i" (concat "sine=frequency=1000:duration=" 
duration-audio-stream)
+   path))
+
+(cl-defun create-sample-media-file-1-audio-stream-1-video-stream (&key
+                                                                  path
+                                                                  
duration-video-stream
+                                                                  
duration-audio-stream)
+  "Create a sample media file with 1 audio stream and 1 video stream.
+
+PATH is the absolute path for the output file. It must be a
+string.
+
+AUDIO-DURATION is the duration in seconds for the audio
+stream. It must be a string.
+
+VIDEO-DURATION is the duration in seconds for the video stream. It
+must be a string."
+  (call-process
+   ;; The ffmpeg command shown below can create files with the
+   ;; extensions shown below (tested using ffmpeg version
+   ;; 4.4.2-0ubuntu0.22.04.1)
+   ;; + audio extensions: wav ogg mp3 opus m4a
+   ;; + video extensions: mkv mp4 webm avi ts ogv"
+   "ffmpeg"
+   nil
+   nil
+   nil
+   "-v" "error"
+   "-y"
+   ;; Create the video stream
+   "-f" "lavfi" "-i" (concat "testsrc=size=100x100:duration=" 
duration-video-stream)
+   ;; Create the audio stream
+   "-f" "lavfi" "-i" (concat "sine=frequency=1000:duration=" 
duration-audio-stream)
+   path))
+
+(describe "waveform"
+  (describe "Get duration in milliseconds of a file with a single audio stream"
+    (let (;; `duration-audio-stream' is the duration in seconds for
+          ;; the media file that is used inside the tests.  When
+          ;; `duration-audio-stream' is an integer, ffprobe might
+          ;; report a duration that is slightly greater, so we can't
+          ;; expect the duration reported by ffprobe to be equal to
+          ;; the duration that we passed to ffmpeg when creating the
+          ;; sample media file. For this reason, we define the
+          ;; variables `duration-lower-boundary' and
+          ;; `duration-upper-boundary' to set a tolerance to the
+          ;; reported value by ffprobe.
+          ;;
+          ;; When `duration-audio-stream' changes, the variables
+          ;; `duration-lower-boundary' and
+          ;; `duration-upper-boundary' should be set accordingly."
+          (duration-audio-stream "3")
+          (duration-lower-boundary 3000)
+          (duration-upper-boundary 4000))
+      (describe "audio file"
+        (it "extension .wav"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.wav"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.wav")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .ogg"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.ogg"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.ogg")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .mp3"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.mp3"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.mp3")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .opus"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.opus"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.opus")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .m4a"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.m4a"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.m4a")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary))))
+      (describe "video file"
+        (it "extension .mkv"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.mkv"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.mkv")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .mp4"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.mp4"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.mp4")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .webm"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.webm"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.webm")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .avi"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.avi"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.avi")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .ts"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.ts"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.ts")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary)))
+        (it "extension .ogv"
+          (create-sample-media-file-1-audio-stream
+           :path "/tmp/a.ogv"
+           :duration-audio-stream duration-audio-stream)
+          (let ((duration-ms (subed-waveform-ffprobe-duration-ms 
"/tmp/a.ogv")))
+            (expect duration-ms :to-be-weakly-greater-than 
duration-lower-boundary)
+            (expect duration-ms :to-be-less-than duration-upper-boundary))))))
+  (describe "Get duration in milliseconds of a file with 1 video and 1 audio 
stream"
+    ;; In this group of test cases, we want the duration of the audio
+    ;; stream to be shorter than the duration of the video stream, so
+    ;; that we can make sure that subed-waveform-ffprobe-duration-ms
+    ;; specifically gets the duration of the audio stream.
+    (let ((duration-video-stream "5")
+          (duration-audio-stream "3")
+          (duration-audio-stream-lower-boundary 3000)
+          (duration-audio-stream-upper-boundary 4000))
+      (it "extension .mkv"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.mkv"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.mkv")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary)))
+      (it "extension .mp4"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.mp4"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.mp4")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary)))
+      (it "extension .webm"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.webm"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.webm")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary)))
+      (it "extension .avi"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.avi"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.avi")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary)))
+      (it "extension .ts"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.ts"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.ts")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary)))
+      (it "extension .ogv"
+        (create-sample-media-file-1-audio-stream-1-video-stream
+         :path "/tmp/a.ogv"
+         :duration-video-stream duration-video-stream
+         :duration-audio-stream duration-audio-stream)
+        (let ((duration-ms (subed-waveform-ffprobe-duration-ms "/tmp/a.ogv")))
+          (expect duration-ms :to-be-weakly-greater-than 
duration-audio-stream-lower-boundary)
+          (expect duration-ms :to-be-less-than 
duration-audio-stream-upper-boundary))))))
diff --git a/tests/test-subed-waveform.el.license 
b/tests/test-subed-waveform.el.license
new file mode 100644
index 0000000000..b71ceecb7f
--- /dev/null
+++ b/tests/test-subed-waveform.el.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2024 Rodrigo Morales
+
+SPDX-License-Identifier: GPL-3.0-or-later
\ No newline at end of file



reply via email to

[Prev in Thread] Current Thread [Next in Thread]