public static function webvtt2subrip(WebvttFile $_vtt) { $srt = new SubripFile(); foreach ($_vtt->getCues() as $cue) { $srt->addCue($cue->getText(), SubripCue::ms2tc($cue->getStartMS()), SubripCue::ms2tc($cue->getStopMS())); } return $srt; }
public function testWebvtt2SubripConversion() { // example file from W3C spec $filename = __DIR__ . '/../Fixtures/example-1.vtt'; $file = new WebvttFile($filename); $content = "1\n00:00:00,000 --> 00:00:20,000\n<v Fred>Hi, my name is Fred,\nnice to meet you.\n\n2\n00:00:02,500 --> 00:00:22,500\n<v Bill>Hi, I'm Bill.\n\n3\n00:00:05,000 --> 00:00:25,000\n<v Fred>Would you like to get a coffee?\n\n4\n00:00:07,500 --> 00:00:27,500\n<v Bill>Sure! I've only had one today.\n\n5\n00:00:10,000 --> 00:00:30,000\n<v Fred>This is my fourth!\n\n6\n00:00:12,500 --> 00:00:32,500\n<v Fred>OK, let's go.\n\n"; $this->assertEquals($content, $file->convertTo('subrip')->build()->getFileContent()); }
/** * Generates sprite and WebVTT for selected video * * @throws \Exception */ public function generate() { // create temporay directory $tempDir = new Tempdir('sprite'); $tempDir->addPlugin(new ListFiles()); // get basic info about video $ffprobe = FFProbe::create()->format($this->getSource()); $duration = floatval($ffprobe->get('duration')); // check if sample rate is high enough to reach desired minimum amount of thumbnails if ($duration <= $this->getMinThumbs()) { // we only have a 1 second resolution, so we can't get lower than 1 obviously $this->setRate(1); } else { if ($duration / $this->getRate() < $this->getMinThumbs()) { // sample rate too high, let's adjust rate a little $this->setRate(floor($duration / $this->getMinThumbs())); } } // capture images to tempdir for ($i = 0; $i <= $duration; $i += $this->getRate()) { $cmd = sprintf('ffmpeg -y -ss %d -i %s -frames:v 1 -filter:v scale=%d:-1 %s/%04d.jpg', $i, $this->getSource(), $this->getWidth(), $tempDir->getPath(), floor($i / $this->getRate())); $proc = new Process($cmd); $proc->setTimeout(null); $proc->run(); if (!$proc->isSuccessful()) { throw new \RuntimeException($cmd . ":" . $proc->getErrorOutput()); } } // combine all images to one sprite with quadratic tiling $gridSize = ceil(sqrt(count($tempDir->listFiles()))); $firstImage = Image::make(sprintf('%s/0001.jpg', $tempDir->getPath())); $spriteFile = sprintf('%s/%s.jpg', $this->getOutputDirectory(), $this->getPrefix()); $spriteUrl = empty($this->getUrlPrefix()) ? basename($spriteFile) : sprintf('%s/%s', $this->getUrlPrefix(), basename($spriteFile)); $cmd = sprintf('montage %1$s/*.jpg -tile %2$dx -geometry %3$dx%4$d+0+0 %5$s', $tempDir->getPath(), $gridSize, $firstImage->width(), $firstImage->height(), $spriteFile); $proc = new Process($cmd); $proc->run(); if (!$proc->isSuccessful()) { throw new RuntimeException($proc->getErrorOutput()); } // create WebVTT output $vttFile = sprintf('%s/%s.vtt', $this->getOutputDirectory(), $this->getPrefix()); $vtt = new WebvttFile(); for ($i = 0; $i < count($tempDir->listFiles()); $i++) { $start = $i * $this->getRate(); $end = ($i + 1) * $this->getRate(); $x = $i % $gridSize * $firstImage->width(); $y = floor($i / $gridSize) * $firstImage->height(); $vtt->addCue(new WebvttCue($this->secondsToCue($start), $this->secondsToCue($end), sprintf('%s#xywh=%d,%d,%d,%d', $spriteUrl, $x, $y, $firstImage->width(), $firstImage->height()))); } $vtt->build(); $vtt->save($vttFile); }