From dd3cae6f70815817c6f0ec46fd2712ad61f50b5c Mon Sep 17 00:00:00 2001 From: ccd0 Date: Sat, 30 Nov 2013 12:18:35 -0800 Subject: [PATCH] improved frame extraction (including alpha) --- README.md | 1 - matroska.php | 10 ++-- videodata.php | 124 ++++++++++++++++++++------------------------------ 3 files changed, 54 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index aaa9b264..404aa120 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ And add this to stylesheets/style.css: float: left; margin: 10px 20px; border: none; - background: #aaa; } div.post video.post-image { padding: 0px; diff --git a/matroska.php b/matroska.php index ff6ce03d..17ff344a 100644 --- a/matroska.php +++ b/matroska.php @@ -497,7 +497,7 @@ function readMatroska($fileHandle) { return $root; } -function encodeVarInt($n) { +function ebmlEncodeVarInt($n) { $data = ''; $flag = 0x80; while ($n >= $flag) { @@ -512,11 +512,11 @@ function encodeVarInt($n) { return $data; } -function encodeElementName($name) { +function ebmlEncodeElementName($name) { global $EBML_ELEMENTS; - return encodeVarInt($EBML_ELEMENTS->id($name)); + return ebmlEncodeVarInt($EBML_ELEMENTS->id($name)); } -function encodeElement($name, $content) { - return encodeElementName($name) . encodeVarInt(strlen($content)) . $content; +function ebmlEncodeElement($name, $content) { + return ebmlEncodeElementName($name) . ebmlEncodeVarInt(strlen($content)) . $content; } diff --git a/videodata.php b/videodata.php index ec302fdc..15ed595d 100644 --- a/videodata.php +++ b/videodata.php @@ -1,76 +1,53 @@ content()->readAll()) ); - $cues = encodeElement('Cues', - encodeElement('CuePoint', - encodeElement('CueTime', "\x00") - . encodeElement('CueTrackPositions', - encodeElement('CueTrack', "\x01") - . encodeElement('CueClusterPosition', chr($lenSeekHead + strlen($info) + strlen($tracks) + $lenCues)) + $cues = ebmlEncodeElement('Cues', + ebmlEncodeElement('CuePoint', + ebmlEncodeElement('CueTime', "\x00") + . ebmlEncodeElement('CueTrackPositions', + ebmlEncodeElement('CueTrack', pack('N', $trackNumber)) + . ebmlEncodeElement('CueClusterPosition', pack('N', $lenSeekHead + strlen($info) + strlen($tracks) + $lenCues)) ) ) ); - $seekHead = encodeElement('SeekHead', - encodeElement('Seek', - encodeElement('SeekID', encodeElementName('Info')) - . encodeElement('SeekPosition', chr($lenSeekHead)) - ) - . encodeElement('Seek', - encodeElement('SeekID', encodeElementName('Tracks')) - . encodeElement('SeekPosition', chr($lenSeekHead + strlen($info))) - ) - . encodeElement('Seek', - encodeElement('SeekID', encodeElementName('Cues')) - . encodeElement('SeekPosition', chr($lenSeekHead + strlen($info) + strlen($tracks))) - ) - . encodeElement('Seek', - encodeElement('SeekID', encodeElementName('Cluster')) - . encodeElement('SeekPosition', chr($lenSeekHead + strlen($info) + strlen($tracks) + $lenCues)) - ) - ); - $cluster = "\x1F\x43\xB6\x75\x08" . pack('N', $size + 13) . ( - //. encodeElement('Cluster', - encodeElement('Timecode', "\x00") - . "\xA3\x08" . pack('N', $size + 4) . ("\x81\x00\x00\x80" . $data) - //. encodeElement('SimpleBlock', "\x81\x00\x00\x80" . $data) + if (strlen($cues) != $lenCues) throw new Exception('length of Cues element wrong'); + $cluster = ebmlEncodeElement('Cluster', + ebmlEncodeElement('Timecode', "\x00") + . ebmlEncodeElement($frame->name(), $frame->content()->readAll()) + . ebmlEncodeElement('Void', '') ); - $segment = "\x18\x53\x80\x67\x08" . pack('N', $size + 173) . ( - // . encodeElement('Segment', - $seekHead . $info . $tracks . $cues . $cluster + $seekHead = ebmlEncodeElement('SeekHead', + matroskaSeekElement('Info', $lenSeekHead) + . matroskaSeekElement('Tracks', $lenSeekHead + strlen($info)) + . matroskaSeekElement('Cues', $lenSeekHead + strlen($info) + strlen($tracks)) + . matroskaSeekElement('Cluster', $lenSeekHead + strlen($info) + strlen($tracks) + $lenCues) ); + if (strlen($seekHead) != $lenSeekHead) throw new Exception('length of SeekHead element wrong'); + $segment = ebmlEncodeElement('Segment', $seekHead . $info . $tracks . $cues . $cluster); return $ebml . $segment; } @@ -79,23 +56,20 @@ function firstVPxFrame($segment, $trackNumber, $skip=0) { foreach($segment as $x1) { if ($x1->name() == 'Cluster') { $cluserTimecode = $x1->Get('Timecode'); - foreach($x1 as $x2) { + foreach($x1 as $blockGroup) { $blockRaw = NULL; - if ($x2->name() == 'SimpleBlock') { - $blockRaw = $x2->value(); - } elseif ($x2->name() == 'BlockGroup') { - $blockRaw = $x2->get('Block'); + if ($blockGroup->name() == 'SimpleBlock') { + $blockRaw = $blockGroup->value(); + } elseif ($blockGroup->name() == 'BlockGroup') { + $blockRaw = $blockGroup->get('Block'); } if (isset($blockRaw)) { $block = new MatroskaBlock($blockRaw); - if ($block->trackNumber == $trackNumber) { - $frame = $block->frames[0]; - if ($block->keyframe) { - if (!isset($cluserTimecode) || $cluserTimecode + $block->timecode >= $skip) { - return $frame; - } elseif (!isset($frame1)) { - $frame1 = $frame; - } + if ($block->trackNumber == $trackNumber && $block->keyframe) { + if (!isset($cluserTimecode) || $cluserTimecode + $block->timecode >= $skip) { + return $blockGroup; + } elseif (!isset($frame1)) { + $frame1 = $blockGroup; } } } @@ -175,7 +149,7 @@ function videoData($filename) { } $frame = firstVPxFrame($segment, $trackNumber, $skip); if (!isset($frame)) throw new Exception('no keyframes'); - $data['frame'] = muxVPxFrame($pixelWidth, $pixelHeight, $codecID, $frame->readAll()); + $data['frame'] = muxVPxFrame($trackNumber, $videoTrack, $frame); } catch (Exception $e) { error_log($e->getMessage());