Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Smpte Laravel Package

fireworkweb/smpte

A PHP package for working with SMPTE timecodes: parse and validate timecode strings, convert between timecodes, frames, and seconds, and handle drop-frame and non-drop-frame rates for video, broadcast, and media applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a single, dependency-free value object. There is no service provider, facade, config file, or published assets — installation is one line and then you read one class.

composer require fireworkweb/smpte
use Fireworkweb\SMPTE\SMPTE;

$tc = new SMPTE('01:23:45:12', 25);

echo $tc;            // 01:23:45:12
$tc->toFrames();     // 125637
$tc->toSeconds();    // float, frame-accurate

Where to look first:

  1. src/SMPTE.php — the entire public API lives here (parse, toFrames(), toSeconds(), and the reverse constructors). It is small enough to read end-to-end before you use it; do that rather than trusting README snippets alone.
  2. The README examples for the exact static constructor names (fromFrames, fromSeconds, or similar) — confirm signatures against the source, since the surface is tiny but not heavily documented.
  3. composer.json for the PHP version constraint, so you know whether the 2024-11-05 release drops into your oldest supported runtime.

First real use case: you have frame counts or seconds coming out of a media pipeline (ffprobe, an upload transcode, an edit decision list) and you need to show or exchange SMPTE timecode — HH:MM:SS:FF — in a timeline, an export, or a broadcast rundown. Parse once at the ingestion boundary, keep integers in your domain, and render timecode only at the edges.

Implementation Patterns

Store frames, render timecode. The most robust pattern is to persist an integer frame count (plus the frame rate, plus a drop-frame flag) and treat SMPTE as a presentation-layer helper:

// migration: clips.duration_frames (int), clips.fps (decimal), clips.drop_frame (bool)
public function getDurationTimecodeAttribute(): string
{
    return (string) new SMPTE(
        $this->duration_frames,
        $this->fps,
        $this->drop_frame
    );
}

Arithmetic goes through frames, never through strings. Summing a rundown of clips by string manipulation is where off-by-one bugs breed:

$total = collect($clips)
    ->sum(fn ($clip) => (new SMPTE($clip->timecode, $clip->fps))->toFrames());

$rundown = new SMPTE($total, $fps);

Wrap it in your own Timecode value object. Given the package's size and install base, define a thin application-level class (or Eloquent cast) that owns the fps and drop-frame policy and delegates to SMPTE. That gives you a single seam to swap implementations later, and a single place to validate input.

final class Timecode
{
    private function __construct(
        public readonly int $frames,
        public readonly float $fps,
        public readonly bool $dropFrame,
    ) {}

    public static function parse(string $tc, float $fps, bool $df = false): self
    {
        $smpte = new SMPTE($tc, $fps, $df);
        return new self($smpte->toFrames(), $fps, $df);
    }

    public function __toString(): string
    {
        return (string) new SMPTE($this->frames, $this->fps, $this->dropFrame);
    }
}

Adapters for export formats. SRT, WebVTT, and ffmpeg all want something slightly different from SMPTE. Keep those as toSrt(), toVtt(), toFfmpeg() methods on your wrapper, each derived from toSeconds() or toFrames() — do not reimplement timecode parsing.

public function toSrt(): string // 00:01:23,480
{
    $seconds = $this->smpte->toSeconds();
    // format with comma milliseconds; floor, don't round, to avoid drift on concatenation
}

Fixtures you can assert on. Pin down canonical conversions as PHPUnit tests so an upstream change can't silently shift results: at 25 fps, one hour is exactly 90000 frames and 3600 seconds; at 24 fps, 00:00:00:23 + 1 frame rolls the seconds field.

Use it at the seams of a media pipeline. Practical spots: an upload handler that records duration_frames from ffprobe, an admin UI that shows timecode next to a video scrubber, a CSV/broadcast export that must be in HH:MM:SS:FF, and a subtitle generator that needs frame-accurate in/out points.

Gotchas and Tips

  • 29.97 is not 30. Pass the actual project rate. Drop-frame and non-drop-frame produce different timecodes for the same wall-clock duration; mixing them silently introduces drift that compounds over a long timeline.
  • Drop-frame is an explicit policy, not a formatting detail. Semicolon (HH:MM:SS;FF) is the common convention for flagging drop-frame, but do not assume the parser infers it from the separator. Carry (fps, dropFrame) alongside every stored timecode and pass both explicitly.
  • Validate the frame component. FF must be less than the frame rate. Decide up front whether invalid input throws or coerces, and enforce it in your wrapper so bad values never reach the library.
  • toSeconds() is floating-point. Round for display, floor for frame math, and never round-trip seconds → timecode → seconds expecting bit-exact equality. Frames are the lossless representation.
  • It is a duration, not a timestamp. There is no date, timezone, or DST semantics here. Do not hand an SMPTE value to Carbon or use it to schedule an actual broadcast event — use it for offsets, lengths, and positions on a timeline.
  • Negative values and offsets. "Five frames before the cut" produces a negative frame count. Handle the negative case in your wrapper (clamp or reject) rather than relying on the library's formatting.
  • Off-by-one at boundaries. Rounding errors usually show up when a frames value lands exactly on a second boundary. Test fps - 1, fps, and fps + 1 frames explicitly.
  • Small package, small blast radius. Seven stars and zero dependents means very few people have exercised edge cases before you. Pin the exact version ("fireworkweb/smpte": "x.y.z") rather than using a caret constraint, and keep your own tests around the conversions your app depends on.
  • Extension points are minimal by design. There are no interfaces or driver abstractions to hook into. Composition (your own Timecode class) beats inheritance here — it keeps the third-party import confined to one file if you ever need to replace it.
  • Debugging recipe. When a timecode looks wrong, print (string) $tc, toFrames(), and toSeconds() side by side for the same input. In practice the culprit is the frame rate passed in, not the library.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator