diff --git a/DASH/IOP/impl/validateSegment.php b/DASH/IOP/impl/validateSegment.php index 0b3c656a..14c7aee2 100644 --- a/DASH/IOP/impl/validateSegment.php +++ b/DASH/IOP/impl/validateSegment.php @@ -12,6 +12,6 @@ if (!$xml) { return; } - -$this->validateSegmentCommon($xml); -$this->validateSegmentOnDemand($xml); +// TODO: we should probably romove these checks for files existance. +$this->validateSegmentCommon($representation); +$this->validateSegmentOnDemand($representation); diff --git a/DASH/IOP/impl/validateSegmentCommon.php b/DASH/IOP/impl/validateSegmentCommon.php index 596f10de..691110e6 100644 --- a/DASH/IOP/impl/validateSegmentCommon.php +++ b/DASH/IOP/impl/validateSegmentCommon.php @@ -2,15 +2,17 @@ global $mpdHandler, $logger; +/** @var DASHIF\RepresentationInterface $representation */ + $selectedPeriod = $mpdHandler->getSelectedPeriod(); $selectedAdaptation = $mpdHandler->getSelectedAdaptationSet(); $selectedRepresentation = $mpdHandler->getSelectedRepresentation(); $period = $mpdHandler->getFeatures()['Period'][$selectedPeriod]; -$adaptation_set = $period['AdaptationSet'][$selectedAdaptationSet]; -$representation = $adaptation_set['Representation'][$selectedRepresentation]; -$codecs = ($representation['codecs']) ? $representation['codecs'] : $adaptation_set['codecs']; -$mimeType = ($representation['mimeType']) ? $representation['mimeType'] : $adaptation_set['mimeType']; +$adaptation_set = $period['AdaptationSet'][$selectedAdaptation]; +$repinfo = $adaptation_set['Representation'][$selectedRepresentation]; +$codecs = ($repinfo['codecs']) ? $repinfo['codecs'] : $adaptation_set['codecs']; +$mimeType = ($repinfo['mimeType']) ? $repinfo['mimeType'] : $adaptation_set['mimeType']; $bitstreamSwitching = ($adaptation_set['bitstreamSwitching']) ? $adaptation_set['bitstreamSwitching'] : $period['bitstreamSwitching']; @@ -38,25 +40,25 @@ "Representation $selectedRepresentation (codecs $codecs)." ); - $codecBoxes = $xml->getElementsByTagName('avcC'); + $codecBoxes = $representation->getAVCCBoxes(); $logger->test( "DASH-IF IOP 4.3", "Section 6.2.5.2", "For AVC video data, if the @bitstreamswitching flag is set to true, all Representations SHALL include " . "Initialization Segment containing 'avcC' box", - $codecBoxes->length > 0, + $codecBoxes && count($codecBoxes) > 0, "FAIL", - $codecBoxes->length . " 'avcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . + count($codecBoxes) . " 'avcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation.", "No 'avcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation." ); - if ($codecBoxes->length > 0) { + if ($codecBoxes && count($codecBoxes) > 0) { $spsFound = false; $ppsFound = false; - $nalBoxes = $codec_box->item(0)->getElementsByTagName('NALUnit'); + $nalBoxes = $codecBoxes[0]->NALUnits; foreach ($nalBoxes as $nalBox) { - $unitType = $nalBox->getAttribute('nal_unit_type'); + $unitType = $nalBox->type; if (hexdec($unitType) == 7) { $spsFound = true; } @@ -93,26 +95,26 @@ "Representation $selectedRepresentation (codecs $codecs)." ); - $codecBoxes = $xml->getElementsByTagName('hvcC'); + $codecBoxes = $representation->getHVCCBoxes(); $logger->test( "DASH-IF IOP 4.3", "Section 6.2.5.2", "For HEVC video data, if the @bitstreamswitching flag is set to true, all Representations SHALL include " . "Initialization Segment containing 'hvcC' box", - $codecBoxes->length > 0, + $codecBoxes && count($codecBoxes) > 0, "FAIL", - $codecBoxes->length . " 'hvcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . + count($codecBoxes) . " 'hvcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation.", "No 'hvcC' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation." ); - if ($codecBoxes->length > 0) { - $vps_found = false; - $sps_found = false; - $pps_found = false; - $nalBoxes = $codecBoxes->item(0)->getElementsByTagName('NALUnit'); + if ($codecBoxes && count($codecBoxes) > 0) { + $vpsFound = false; + $spsFound = false; + $ppsFound = false; + $nalBoxes = $codecBoxes[0]->NALUnits; foreach ($nalBoxes as $nalBox) { - $unitType = $nalBox->getAttribute('nal_unit_type'); + $unitType = $nalBox->type; if ($unitType == 32) { $vpsFound = true; } @@ -140,7 +142,7 @@ } if ($isAvc || $isHevc) { - $elstBoxes = $xml->getElementsByTagName('elst'); + $elstBoxes = $representation->getELSTBoxes(); $representationProfiles = $mpdHandler->getProfiles[$selectedPeriod][$selectedAdaptation][$selectedRepresentation]; if ( !(strpos($representationProfiles, 'http://dashif.org/guidelines/dash-if-ondemand') !== false || @@ -151,7 +153,7 @@ "DASH-IF IOP 4.3", "Section 6.2.5.2", "Edit lists SHALL NOT be present in video Adaptation Sets unless they are offered in On-Demand profile", - $elstBoxes->length == 0, + !$elstBoxes || count($elstBoxes) == 0, "FAIL", "No edit lists found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation", @@ -160,15 +162,15 @@ ); } - $trunElements = $xml->getElementsByTagName('trun'); - $tfdtElements = $xml->getElementsByTagName('tfdt'); + $trunElements = $representation->getTRUNBoxes(); + $tfdtElements = $representation->getTFDTBoxes(); $firstSampleCompTime = ''; $firstSampleDecTime = ''; - if ($trunElements->length > 0) { - $firstSampleCompTime = $xml_trun[0]->getAttribute('earliestCompositionTime'); + if ($trunElements && count($trunElements) > 0) { + $firstSampleCompTime = $trunElements[0]->earliestCompositionTime; } - if ($tfdtElements->length > 0) { - $firstSampleDecTime = $tfdt[0]->getAttribute('baseMediaDecodeTime'); + if ($tfdtElements && count($tfdtElements) > 0) { + $firstSampleDecTime = $tfdtElements[0]->baseMediaDecodeTime; } $logger->test( diff --git a/DASH/IOP/impl/validateSegmentOnDemand.php b/DASH/IOP/impl/validateSegmentOnDemand.php index 8b37d9f0..00dd72fc 100644 --- a/DASH/IOP/impl/validateSegmentOnDemand.php +++ b/DASH/IOP/impl/validateSegmentOnDemand.php @@ -15,17 +15,17 @@ return; } -$sidxBoxes = $xml->getElementsByTagName('sidx'); +$sidxBoxes = $representation->getSIDXBoxes(); $logger->test( "DASH-IF IOP 4.3", "Section 3.10.3.2", "Only a single 'sidx' SHALL be present", - $sidxBoxes->length == 1, + $sidxBoxes && count($sidxBoxes) == 1, "FAIL", "Exactly one 'sidx' box found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation", - $sidxBoxes->length . " 'sidx' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . + ($sidxBoxes ? count($sidxBoxes) : 0) . " 'sidx' boxes found for Period $selectedPeriod Adaptation Set $selectedAdaptation " . "Representation $selectedRepresentation" ); diff --git a/DASH/IOP/module.php b/DASH/IOP/module.php index fe4fa850..35759cdc 100644 --- a/DASH/IOP/module.php +++ b/DASH/IOP/module.php @@ -66,22 +66,32 @@ private function validateMPDMixedOnDemand() public function hookRepresentation() { parent::hookRepresentation(); - $this->validateSegment(); + global $validatorWrapper, $mpdHandler; + $thisRepresentation = [ + $mpdHandler->getSelectedPeriod(), + $mpdHandler->getSelectedAdaptationSet(), + $mpdHandler->getSelectedRepresentation() + ]; + $validatorWrapper->analyzeSingle( + $thisRepresentation, + $this, + 'validateSegment' + ); } - private function validateSegment() + public function validateSegment($representation) { - include 'impl/validateSegment.php'; + return include 'impl/validateSegment.php'; } - private function validateSegmentCommon($xml) + public function validateSegmentCommon($representation) { - include 'impl/validateSegmentCommon.php'; + return include 'impl/validateSegmentCommon.php'; } - private function validateSegmentOnDemand($xml) + public function validateSegmentOnDemand($representation) { - include 'impl/validateSegmentOnDemand.php'; + return include 'impl/validateSegmentOnDemand.php'; } public function hookAdaptationSet() diff --git a/Utils/RepresentationInterface.php b/Utils/RepresentationInterface.php index 95f88186..573b1b9f 100644 --- a/Utils/RepresentationInterface.php +++ b/Utils/RepresentationInterface.php @@ -153,4 +153,35 @@ public function hasBox($boxName) { return false; } + + public function getAVCCBoxes(): array|null + { + return null; + } + + public function getHVCCBoxes(): array|null + { + return null; + } + + public function getELSTBoxes(): array|null + { + return null; + } + + public function getTRUNBoxes(): array|null + { + return null; + } + + public function getTFDTBoxes(): array|null + { + return null; + } + + public function getSIDXBoxes(): array|null + { + return null; + } + } diff --git a/Utils/boxes/avccbox.php b/Utils/boxes/avccbox.php new file mode 100644 index 00000000..eed47f63 --- /dev/null +++ b/Utils/boxes/avccbox.php @@ -0,0 +1,12 @@ +NALUnits = array(); // array of NALUnit objects + } + public $NALUnits; +} \ No newline at end of file diff --git a/Utils/boxes/elstbox.php b/Utils/boxes/elstbox.php new file mode 100644 index 00000000..e49d6e98 --- /dev/null +++ b/Utils/boxes/elstbox.php @@ -0,0 +1,11 @@ +NALUnits = array(); // array of NALUnit objects + } + public $NALUnits; +} \ No newline at end of file diff --git a/Utils/boxes/nalunitbox.php b/Utils/boxes/nalunitbox.php new file mode 100644 index 00000000..eb325635 --- /dev/null +++ b/Utils/boxes/nalunitbox.php @@ -0,0 +1,12 @@ +type = null; + } + public $type; +} \ No newline at end of file diff --git a/Utils/boxes/sidxbox.php b/Utils/boxes/sidxbox.php new file mode 100644 index 00000000..9450eac4 --- /dev/null +++ b/Utils/boxes/sidxbox.php @@ -0,0 +1,11 @@ +baseMediaDecodeTime = null; + } + public $baseMediaDecodeTime; +} \ No newline at end of file diff --git a/Utils/boxes/trunbox.php b/Utils/boxes/trunbox.php new file mode 100644 index 00000000..945d3a26 --- /dev/null +++ b/Utils/boxes/trunbox.php @@ -0,0 +1,12 @@ +earliestCompositionTime = null; + } + public $earliestCompositionTime; +} \ No newline at end of file diff --git a/Utils/validators/isoSegmentRepresentation.php b/Utils/validators/isoSegmentRepresentation.php index 228d9e36..49715c04 100644 --- a/Utils/validators/isoSegmentRepresentation.php +++ b/Utils/validators/isoSegmentRepresentation.php @@ -325,4 +325,96 @@ public function getFragmentDurations(): array|null } return $res; } + public function getAVCCBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $avcCNodes = $this->payload->getElementsByTagName('avcC'); + foreach ($avcCNodes as $node) { + $box = new Boxes\AVCCBox(); + $nalUnits = $node->getElementsByTagName('NALUnit'); + foreach ($nalUnits as $nalNode) { + $nal = new Boxes\NALUnit(); + $nal->type = $nalNode->getAttribute('nal_unit_type'); + $box->NALUnits[] = $nal; + } + $res[] = $box; + } + } + return $res; + } + + public function getHVCCBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $hvccNodes = $this->payload->getElementsByTagName('hvcC'); + foreach ($hvccNodes as $node) { + $box = new Boxes\HVCCBox(); + $nalUnits = $node->getElementsByTagName('NALUnit'); + foreach ($nalUnits as $nalNode) { + $nal = new Boxes\NALUnit(); + $nal->type = $nalNode->getAttribute('nal_unit_type'); + $box->NALUnits[] = $nal; + } + $res[] = $box; + } + } + return $res; + } + + public function getELSTBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $elstNodes = $this->payload->getElementsByTagName('elst'); + foreach ($elstNodes as $node) { + $box = new Boxes\ELSTBox(); + $res[] = $box; + } + } + return $res; + } + + public function getTRUNBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $trunNodes = $this->payload->getElementsByTagName('trun'); + foreach ($trunNodes as $node) { + $box = new Boxes\TRUNBox(); + $box->earliestCompositionTime = $node->getAttribute('earliestCompositionTime'); + $res[] = $box; + } + } + return $res; + } + + public function getTFDTBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $tfdtNodes = $this->payload->getElementsByTagName('tfdt'); + foreach ($tfdtNodes as $node) { + $box = new Boxes\TFDTBox(); + $box->baseMediaDecodeTime = $node->getAttribute('baseMediaDecodeTime'); + $res[] = $box; + } + } + return $res; + } + + public function getSIDXBoxes(): array|null + { + $res = array(); + if ($this->payload) { + $sidxNodes = $this->payload->getElementsByTagName('sidx'); + foreach ($sidxNodes as $node) { + $box = new \DASHIF\Boxes\SIDXBox(); + // Add attribute extraction here + $res[] = $box; + } + } + return $res; + } }