Skip to content

Commit

Permalink
Support updating metadata for videos.
Browse files Browse the repository at this point in the history
  • Loading branch information
kohler committed Sep 7, 2023
1 parent 28aeff6 commit 275055d
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 23 deletions.
46 changes: 41 additions & 5 deletions batch/updatedocmetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,28 @@ class UpdateDocMetadata_Batch {
public $conf;
/** @var bool */
public $verbose;
/** @var bool */
public $images = true;
/** @var bool */
public $videos = true;
/** @var bool */
public $pdfs = true;

function __construct(Conf $conf, $arg) {
$this->conf = $conf;
$this->verbose = isset($arg["verbose"]);
if (isset($arg["images"]) || isset($arg["videos"]) || isset($arg["pdfs"])) {
$this->images = $this->videos = $this->pdfs = false;
}
if (isset($arg["images"])) {
$this->images = true;
}
if (isset($arg["videos"])) {
$this->videos = true;
}
if (isset($arg["pdfs"])) {
$this->pdfs = true;
}
}


Expand Down Expand Up @@ -45,19 +63,33 @@ private function run_images_subset($docs) {
DocumentInfo::prefetch_content($docs, DocumentInfo::FLAG_NO_DOCSTORE);
foreach ($docs as $doc) {
$info = Mimetype::content_info(null, $doc->mimetype, $doc);
$upd = [];
$m = $doc->metadata() ?? (object) [];
if (isset($info["width"]) && !isset($m->width)) {
$doc->set_prop("width", $info["width"]);
}
if (isset($info["height"]) && !isset($m->height)) {
$doc->set_prop("height", $info["height"]);
}
$upd = $doc->prop_update();
$doc->save_prop();
if ($this->verbose && !empty($upd)) {
fwrite(STDERR, $doc->export_filename(null, DocumentInfo::ANY_MEMBER_FILENAME) . " [{$doc->filename} #{$doc->paperId}/{$doc->paperStorageId}]: " . (empty($upd) ? "-" : json_encode($upd)) . "\n");
}
}
}

private function run_videos() {
$result = $this->conf->qe("select " . $this->conf->document_query_fields() . " from PaperStorage where mimetype like 'video/%'");
$docs = [];
while (($doc = DocumentInfo::fetch($result, $this->conf))) {
$doc->analyze_content();
$upd = $doc->prop_update();
$doc->save_prop();
if ($this->verbose && !empty($upd)) {
fwrite(STDERR, $doc->export_filename() . " [{$doc->filename} #{$doc->paperId}/{$doc->paperStorageId}]: " . (empty($upd) ? "-" : json_encode($upd)) . "\n");
fwrite(STDERR, $doc->export_filename(null, DocumentInfo::ANY_MEMBER_FILENAME) . " [{$doc->filename} #{$doc->paperId}/{$doc->paperStorageId}]: " . (empty($upd) ? "-" : json_encode($upd)) . "\n");
}
}
Dbl::free($result);
}

private function run_pdf() {
Expand All @@ -75,8 +107,9 @@ private function run_pdf() {

/** @return int */
function run() {
$this->run_images();
$this->run_pdf();
$this->images && $this->run_images();
$this->videos && $this->run_videos();
$this->pdfs && $this->run_pdf();
return 0;
}

Expand All @@ -87,7 +120,10 @@ static function make_args($argv) {
"name:,n: !",
"config: !",
"help,h !",
"verbose,V Be verbose."
"verbose,V Be verbose.",
"images Run on images.",
"videos Run on videos.",
"pdf Run on PDFs."
)->description("Update HotCRP document metadata.
Usage: php batch/updatedocmetadata.php [-n CONFID | --config CONFIG]")
->helpopt("help")
Expand Down
83 changes: 72 additions & 11 deletions lib/isovideomimetype.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ class ISOVideoMimetype implements JsonSerializable {
private $data;
/** @var int */
private $bound;
/** @var bool */
private $verbose = false;
/** @var int */
private $depth = 0;

/** @var int */
private $flags = 0;
Expand Down Expand Up @@ -36,6 +40,7 @@ class ISOVideoMimetype implements JsonSerializable {
const TF_AUDIO = 1;
const TF_VIDEO = 2;
const TF_ASPECT = 4;
const TF_PREVIEW = 8;


private function __construct() {
Expand All @@ -62,6 +67,13 @@ static function make_file($filename, $prefix = null) {
return $vm;
}

/** @param bool $v
* @return $this */
function set_verbose($v) {
$this->verbose = $v;
return $this;
}

/** @param ISOVideoFragment $data
* @param int $pos
* @param int $epos
Expand Down Expand Up @@ -128,6 +140,11 @@ function iso_box_at($data, $pos, $bound) {
$box->cpos = $xpos;
$box->bound = $pos + $size;
$box->data = $data;
if ($this->verbose) {
fwrite(STDERR, sprintf("%s%s [%d,%d)\n",
str_repeat(" ", $this->depth),
self::unparse_tag($type), $pos, $pos + $size));
}
return $box;
}

Expand All @@ -146,7 +163,8 @@ static function unparse_tag($type) {
/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound */
function walk_moov($data, $pos, $bound) {
private function walk_moov($data, $pos, $bound) {
++$this->depth;
while (($box = $this->iso_box_at($data, $pos, $bound))) {
$data = $box->data;
if ($box->type === 0x6d766864 /* `mvhd` */) {
Expand All @@ -158,12 +176,13 @@ function walk_moov($data, $pos, $bound) {
}
$pos = $box->bound;
}
--$this->depth;
}

/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound */
function walk_mvhd($data, $pos, $bound) {
private function walk_mvhd($data, $pos, $bound) {
if ($pos + 32 > $data->epos
&& !($data = $this->ensure($data, $pos, $pos + 32))) {
return;
Expand Down Expand Up @@ -192,7 +211,8 @@ function walk_mvhd($data, $pos, $bound) {
/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound */
function walk_trak($data, $pos, $bound) {
private function walk_trak($data, $pos, $bound) {
++$this->depth;
$track = new ISOVideoTrack;
while (($box = $this->iso_box_at($data, $pos, $bound))) {
$data = $box->data;
Expand All @@ -206,13 +226,14 @@ function walk_trak($data, $pos, $bound) {
if ($track->flags !== null) {
$this->tracks[] = $track;
}
--$this->depth;
}

/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound
* @param ISOVideoTrack $track */
function walk_tkhd($data, $pos, $bound, $track) {
private function walk_tkhd($data, $pos, $bound, $track) {
if ($pos + 84 > $data->epos
&& !($data = $this->ensure($data, $pos, $pos + 84))) {
return;
Expand All @@ -232,36 +253,47 @@ function walk_tkhd($data, $pos, $bound, $track) {
}
if (($duration & $mask) !== $mask) {
$track->duration = $duration;
} else {
$duration = null;
}
if ($pos + $xoff + 60 > $data->epos
&& !($data = $this->ensure($data, $pos, $pos + $xoff + 60))) {
return;
}
$track->width = Mimetype::be32at($data->s, $pos + $xoff + 52 - $data->pos);
$track->height = Mimetype::be32at($data->s, $pos + $xoff + 56 - $data->pos);
if ($this->verbose) {
fwrite(STDERR, sprintf("%s tkhd: flags %x, duration %s, width %g, height %g\n",
str_repeat(" ", $this->depth),
$vflags & 0xFFFFFF,
json_encode($duration),
$track->width / 65536., $track->height / 65536.));
}
}


/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound
* @param ISOVideoTrack $track */
function walk_mdia($data, $pos, $bound, $track) {
private function walk_mdia($data, $pos, $bound, $track) {
++$this->depth;
while (($box = $this->iso_box_at($data, $pos, $bound))) {
$data = $box->data;
if ($box->type === 0x68646c72 /* `hdlr` */) {
$this->walk_hdlr($data, $box->cpos, $box->bound, $track);
return;
break;
}
$pos = $box->bound;
}
--$this->depth;
}

/** @param ISOVideoFragment $data
* @param int $pos
* @param int $bound
* @param ISOVideoTrack $track */
function walk_hdlr($data, $pos, $bound, $track) {
private function walk_hdlr($data, $pos, $bound, $track) {
if ($bound - $pos < 24
|| ($bound > $data->epos
&& !($data = $this->ensure($data, $pos, $bound)))) {
Expand All @@ -271,6 +303,10 @@ function walk_hdlr($data, $pos, $bound, $track) {
return;
}
$track->handler = Mimetype::be32at($data->s, $pos + 8 - $data->pos);
if ($this->verbose) {
fwrite(STDERR, sprintf("%s hdlr: %s\n",
str_repeat(" ", $this->depth), self::unparse_tag($track->handler)));
}
}


Expand Down Expand Up @@ -327,16 +363,41 @@ function analyze() {
}
if ($tr->handler === 0x76696465 /* `vide` */) {
$this->tflags |= self::TF_VIDEO;
if ($tr->width === null || $tr->height === null) {
continue;
}
$w = (int) round($tr->width / 65536.0);
$h = (int) round($tr->height / 65536.0);
// if aspect ratio, ignore unless plausibly pixels
if (($tr->flags & 8) !== 0) {
if ($this->width !== null
|| $w < 400 || $w > 8000
|| $h < 400 || $h > 8000) {
continue;
}
$this->tflags |= self::TF_ASPECT;
} else {
if ($this->width === null && $tr->width !== null) {
$this->width = (int) round($tr->width / 65536.0);
if ($this->width !== null
&& ($this->tflags & self::TF_ASPECT) === 0) {
continue;
}
if ($this->height === null && $tr->height !== null) {
$this->height = (int) round($tr->height / 65536.0);
$this->tflags &= ~self::TF_ASPECT;
}
// if preview-only, override
if (($tr->flags & 2) === 0) {
if ($this->width !== null) {
continue;
}
$this->tflags |= self::TF_PREVIEW;
} else {
if ($this->width !== null
&& ($this->tflags & self::TF_PREVIEW) === 0) {
continue;
}
$this->tflags &= ~self::TF_PREVIEW;
}
$this->width = $w;
$this->height = $h;
} else if ($tr->handler === 0x736f756e /* `soun` */) {
$this->tflags |= self::TF_AUDIO;
}
Expand Down
15 changes: 15 additions & 0 deletions src/documentinfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,21 @@ function abort_prop() {
$this->_old_prop = null;
}

function prop_update() {
$j = [];
foreach ($this->_old_prop ?? [] as $prop => $v) {
if ($prop === "metadata") {
$m = $this->metadata();
foreach ((array) $v as $prop1 => $v1) {
$j[$prop1] = $m->$prop1 ?? null;
}
} else {
$j[$prop] = $this->$prop;
}
}
return $j;
}

function load_metadata() {
if ($this->paperStorageId > 0) {
$row = Dbl::fetch_first_object($this->conf->dblink,
Expand Down
12 changes: 5 additions & 7 deletions test/t_mimetype.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ function test_gif() {
}

function xxx_test_mp4() {
$mt = ISOVideoMimetype::make_file("/Users/kohler/Downloads/sigcomm23-paper130-10_minute_presentation_video.mp4");
$mt->analyze();
error_log(json_encode($mt->content_info()));

$mt = ISOVideoMimetype::make_file("/Users/kohler/Downloads/sigcomm23-paper1037-10_minute_presentation_video/MoMA v1.0.3.mp4");
$mt->analyze();
error_log(json_encode($mt->content_info()));
foreach (glob("/Users/kohler/Downloads/sigcomm23-10_minute_presentation_video/*.mp4") as $f) {
$mt = ISOVideoMimetype::make_file($f)->set_verbose(true);
$mt->analyze();
error_log($f. ": " . json_encode($mt->content_info()));
}
}
}

0 comments on commit 275055d

Please sign in to comment.