diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7727ade..db35448 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,6 @@ name: ci on: - push: pull_request: env: diff --git a/DESCRIPTION b/DESCRIPTION index d06cbe0..1f7e403 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,9 +1,11 @@ Package: compost -Version: 0.1.0.7 -Title: Video Compositing via FFmpeg -Description: Wraps common FFmpeg filter_complex patterns (overlay, chromakey, - concat, scale, vstack) into clean R functions for video compositing, and - lowers an OpenTimelineIO timeline (via rotio) to a rendered video. +Version: 0.1.0.8 +Title: Video Compositing via 'FFmpeg' +Description: Wraps common 'FFmpeg' filter_complex + patterns (overlay, chromakey, concat, scale, vstack) into clean R + functions for video compositing, and lowers an 'OpenTimelineIO' + timeline (via the 'rotio' package) to a + rendered video. Authors@R: c( person("Troy", "Hernandez", email = "troy@cornball.ai", @@ -11,6 +13,8 @@ Authors@R: c( comment = c(ORCID = "0009-0005-4248-604X")), person("cornball.ai", role = "cph")) License: MIT + file LICENSE +URL: https://github.com/cornball-ai/compost +BugReports: https://github.com/cornball-ai/compost/issues Encoding: UTF-8 SystemRequirements: ffmpeg (>= 5.0) Imports: diff --git a/R/align.R b/R/align.R index 1006d83..9bc433e 100644 --- a/R/align.R +++ b/R/align.R @@ -107,6 +107,10 @@ align_audio <- function(clip, narration, sr = 8000L, hop = 80L) { #' @return A data frame with one row per chunk: \code{chunk}, \code{file}, #' \code{frames}, \code{fps}, \code{offset} (narration seconds), #' \code{correlation}, and \code{overlap} (frames; 0 for the first chunk). +#' @examples +#' \dontrun{ +#' align_overlaps(c("media/chunk01.mp4", "media/chunk02.mp4"), "audio.mp3") +#' } #' @export align_overlaps <- function(files, narration, fps = 24) { n <- length(files) diff --git a/R/rms.R b/R/rms.R index 58b7737..a03dd67 100644 --- a/R/rms.R +++ b/R/rms.R @@ -7,6 +7,9 @@ #' #' Slices the audio into \code{window}-sample blocks and prints each block's #' overall RMS level (dB) as ametadata to \code{mfile}. +#' @param window Window size in samples. +#' @param mfile Path the ametadata print stream is written to. +#' @return A single ffmpeg filter-chain string. #' @keywords internal .rms_filter <- function(window, mfile) { sprintf(paste0("asetnsamples=%d,astats=metadata=1:reset=1,", @@ -19,6 +22,9 @@ #' The print stream alternates a \code{pts_time:} line and an #' \code{RMS_level=} line per window. Digital silence prints \code{-inf}, #' mapped to -120. +#' @param lines Character vector of ffmpeg ametadata print output. +#' @return A list with numeric \code{time} (window centre, seconds) and +#' \code{rms} (RMS level in dB). #' @keywords internal .parse_rms <- function(lines) { tt <- rr <- numeric(length(lines)) diff --git a/cran-comments.md b/cran-comments.md new file mode 100644 index 0000000..7729429 --- /dev/null +++ b/cran-comments.md @@ -0,0 +1,28 @@ +## Submission + +This is a new submission. + +## Test environments + +- Local: Ubuntu 24.04, R release +- Windows 10: R 4.6.0 and R-devel (pre-release), via `R CMD check --as-cran` + +## R CMD check results + +0 errors | 0 warnings | 1 note + +The one NOTE is the expected "New submission" / Maintainer note. + +## Notes for the reviewer + +- **System requirement.** The package wraps the `ffmpeg` command-line tool + (declared in `SystemRequirements:`, version >= 5.0). Every exported function + shells out to `ffmpeg`/`ffprobe`; nothing is reimplemented in R. + +- **`\dontrun` in examples.** All examples are wrapped in `\dontrun{}` rather + than `\donttest{}`. This is deliberate: the examples require both the + `ffmpeg` binary (which is not guaranteed to be present on the check machines) + and user-supplied media files (video/audio that does not ship with the + package). They cannot execute in CRAN's environment, which is the documented + case for `\dontrun` over `\donttest`. The package's tests cover the + command-construction logic without invoking `ffmpeg`. diff --git a/man/align_overlaps.Rd b/man/align_overlaps.Rd index 8414596..c19d8fd 100644 --- a/man/align_overlaps.Rd +++ b/man/align_overlaps.Rd @@ -25,3 +25,8 @@ each join's overlap from the positions: the seconds by which chunk chained chunk's duplicated head and an undersized chunk's shortfall both fall out of where the words actually are. } +\examples{ +\dontrun{ +align_overlaps(c("media/chunk01.mp4", "media/chunk02.mp4"), "audio.mp3") +} +} diff --git a/man/dot-parse_rms.Rd b/man/dot-parse_rms.Rd index 4648f4e..e181bdd 100644 --- a/man/dot-parse_rms.Rd +++ b/man/dot-parse_rms.Rd @@ -5,6 +5,13 @@ \usage{ .parse_rms(lines) } +\arguments{ +\item{lines}{Character vector of ffmpeg ametadata print output.} +} +\value{ +A list with numeric \code{time} (window centre, seconds) and + \code{rms} (RMS level in dB). +} \description{ The print stream alternates a \code{pts_time:} line and an \code{RMS_level=} line per window. Digital silence prints \code{-inf}, diff --git a/man/dot-rms_filter.Rd b/man/dot-rms_filter.Rd index 20722d1..f34d94c 100644 --- a/man/dot-rms_filter.Rd +++ b/man/dot-rms_filter.Rd @@ -5,6 +5,14 @@ \usage{ .rms_filter(window, mfile) } +\arguments{ +\item{window}{Window size in samples.} + +\item{mfile}{Path the ametadata print stream is written to.} +} +\value{ +A single ffmpeg filter-chain string. +} \description{ Slices the audio into \code{window}-sample blocks and prints each block's overall RMS level (dB) as ametadata to \code{mfile}.