dash_timeline_validator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +12 -0
 - data/.rspec +3 -0
 - data/.travis.yml +7 -0
 - data/Gemfile +4 -0
 - data/Gemfile.lock +41 -0
 - data/LICENSE +29 -0
 - data/README.md +44 -0
 - data/Rakefile +6 -0
 - data/bin/console +14 -0
 - data/bin/setup +8 -0
 - data/dash_timeline_validator.gemspec +43 -0
 - data/exe/dash_timeline_validator +10 -0
 - data/lib/dash_timeline_validator.rb +14 -0
 - data/lib/dash_timeline_validator/adaptation_set.rb +17 -0
 - data/lib/dash_timeline_validator/cli.rb +26 -0
 - data/lib/dash_timeline_validator/file.rb +34 -0
 - data/lib/dash_timeline_validator/log.rb +17 -0
 - data/lib/dash_timeline_validator/options.rb +12 -0
 - data/lib/dash_timeline_validator/period.rb +17 -0
 - data/lib/dash_timeline_validator/report.rb +50 -0
 - data/lib/dash_timeline_validator/representation.rb +58 -0
 - data/lib/dash_timeline_validator/segment.rb +67 -0
 - data/lib/dash_timeline_validator/validator.rb +63 -0
 - data/lib/dash_timeline_validator/version.rb +3 -0
 - metadata +155 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 30a521b9bae3596ae9e89cc90d388a722ad5d3ec4f9871d9747af1f46ad94fd1
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 0b5b89822ad89fac58a53a927a4fa257c331de9762c40fa2e304de12ac307f15
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: ea0620b668d4b5803ecba5ce47811cc584eb8b07c757213ea72bf922bc774531da6e524e0971f06f858d50b138d2cbe5f00348c85578888ac4f5898c7b2c72e0
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 90722730b66e4127aa8d26031a62d6eeab56adb7cee875f8d43291e796f353455716f6fd521db3edf9dced3ae386ad22201e7125c193e1a775d58dd6c4e8863a
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                dash_timeline_validator (0.1.0)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  awesome_print (~> 1.8.0)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  iso8601 (~> 0.10.1)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  ox (~> 2.9.0)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 10 
     | 
    
         
            +
              remote: https://rubygems.org/
         
     | 
| 
      
 11 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 12 
     | 
    
         
            +
                awesome_print (1.8.0)
         
     | 
| 
      
 13 
     | 
    
         
            +
                diff-lcs (1.3)
         
     | 
| 
      
 14 
     | 
    
         
            +
                iso8601 (0.10.1)
         
     | 
| 
      
 15 
     | 
    
         
            +
                ox (2.9.4)
         
     | 
| 
      
 16 
     | 
    
         
            +
                rake (10.5.0)
         
     | 
| 
      
 17 
     | 
    
         
            +
                rspec (3.8.0)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  rspec-core (~> 3.8.0)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  rspec-expectations (~> 3.8.0)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  rspec-mocks (~> 3.8.0)
         
     | 
| 
      
 21 
     | 
    
         
            +
                rspec-core (3.8.0)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  rspec-support (~> 3.8.0)
         
     | 
| 
      
 23 
     | 
    
         
            +
                rspec-expectations (3.8.2)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  rspec-support (~> 3.8.0)
         
     | 
| 
      
 26 
     | 
    
         
            +
                rspec-mocks (3.8.0)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  rspec-support (~> 3.8.0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                rspec-support (3.8.0)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 32 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 35 
     | 
    
         
            +
              bundler (~> 2.0)
         
     | 
| 
      
 36 
     | 
    
         
            +
              dash_timeline_validator!
         
     | 
| 
      
 37 
     | 
    
         
            +
              rake (~> 10.0)
         
     | 
| 
      
 38 
     | 
    
         
            +
              rspec (~> 3.0)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            BUNDLED WITH
         
     | 
| 
      
 41 
     | 
    
         
            +
               2.0.1
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            BSD 3-Clause License
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2019, Globo.com
         
     | 
| 
      
 4 
     | 
    
         
            +
            All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 7 
     | 
    
         
            +
            modification, are permitted provided that the following conditions are met:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            1. Redistributions of source code must retain the above copyright notice, this
         
     | 
| 
      
 10 
     | 
    
         
            +
               list of conditions and the following disclaimer.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            2. Redistributions in binary form must reproduce the above copyright notice,
         
     | 
| 
      
 13 
     | 
    
         
            +
               this list of conditions and the following disclaimer in the documentation
         
     | 
| 
      
 14 
     | 
    
         
            +
               and/or other materials provided with the distribution.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            3. Neither the name of the copyright holder nor the names of its
         
     | 
| 
      
 17 
     | 
    
         
            +
               contributors may be used to endorse or promote products derived from
         
     | 
| 
      
 18 
     | 
    
         
            +
               this software without specific prior written permission.
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
         
     | 
| 
      
 21 
     | 
    
         
            +
            AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 22 
     | 
    
         
            +
            IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
         
     | 
| 
      
 23 
     | 
    
         
            +
            DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 24 
     | 
    
         
            +
            FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 25 
     | 
    
         
            +
            DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
         
     | 
| 
      
 26 
     | 
    
         
            +
            SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
         
     | 
| 
      
 27 
     | 
    
         
            +
            CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
         
     | 
| 
      
 28 
     | 
    
         
            +
            OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         
     | 
| 
      
 29 
     | 
    
         
            +
            OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Dash Timeline Validator
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            An MPEG Dash timeline validator. The validator parses the given MPD file (local or from the web) and shows information and errors of the timeline.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 11 
     | 
    
         
            +
            gem 'dash_timeline_validator'
         
     | 
| 
      
 12 
     | 
    
         
            +
            ```
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                $ gem install dash_timeline_validator
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            Run this program passing the manifest path.
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            ```
         
     | 
| 
      
 27 
     | 
    
         
            +
            dash_timeline_validator https://storage.googleapis.com/shaka-live-assets/player-source.mpd
         
     | 
| 
      
 28 
     | 
    
         
            +
            ```
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            To download and check the duration of every chunk, use the environment variable `VERIFY_SEGMENTS_DURATION` as `true`.
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ```
         
     | 
| 
      
 33 
     | 
    
         
            +
            VERIFY_SEGMENTS_DURATION=true dash_timeline_validator https://storage.googleapis.com/shaka-live-assets/player-source.mpd
         
     | 
| 
      
 34 
     | 
    
         
            +
            ```
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/globocom/dash_timeline_validator.
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/console
    ADDED
    
    | 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "bundler/setup"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "dash_timeline_validator"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # You can add fixtures and/or initialization code here to make experimenting
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with your gem easier. You can also use a different console, if you like.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         
     | 
| 
      
 10 
     | 
    
         
            +
            # require "pry"
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Pry.start
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require "irb"
         
     | 
| 
      
 14 
     | 
    
         
            +
            IRB.start(__FILE__)
         
     | 
    
        data/bin/setup
    ADDED
    
    
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "dash_timeline_validator/version"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name = "dash_timeline_validator"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version = DashTimelineValidator::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.authors = ["Ana Carolina Castro"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.email = ["ana.castro@corp.globo.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              spec.summary = %q{MPEG-Dash Timeline Validator}
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.description = %q{MPEG-Dash Timeline Validator.}
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.homepage = "https://github.com/globocom/dash_timeline_validator"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
         
     | 
| 
      
 17 
     | 
    
         
            +
              # to allow pushing to a single host or delete this section to allow pushing to any host.
         
     | 
| 
      
 18 
     | 
    
         
            +
              if spec.respond_to?(:metadata)
         
     | 
| 
      
 19 
     | 
    
         
            +
                spec.metadata["homepage_uri"] = spec.homepage
         
     | 
| 
      
 20 
     | 
    
         
            +
                spec.metadata["source_code_uri"] = "https://github.com/globocom/dash_timeline_validator"
         
     | 
| 
      
 21 
     | 
    
         
            +
                spec.metadata["changelog_uri"] = "https://github.com/globocom/dash_timeline_validator"
         
     | 
| 
      
 22 
     | 
    
         
            +
              else
         
     | 
| 
      
 23 
     | 
    
         
            +
                raise "RubyGems 2.0 or newer is required to protect against " \
         
     | 
| 
      
 24 
     | 
    
         
            +
                      "public gem pushes."
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              # Specify which files should be added to the gem when it is released.
         
     | 
| 
      
 28 
     | 
    
         
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         
     | 
| 
      
 29 
     | 
    
         
            +
              spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
         
     | 
| 
      
 30 
     | 
    
         
            +
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
              spec.bindir = "exe"
         
     | 
| 
      
 33 
     | 
    
         
            +
              spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         
     | 
| 
      
 34 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              spec.add_dependency "iso8601", "~> 0.10.1"
         
     | 
| 
      
 37 
     | 
    
         
            +
              spec.add_dependency "ox", "~> 2.9.0"
         
     | 
| 
      
 38 
     | 
    
         
            +
              spec.add_dependency "awesome_print", "~> 1.8.0"
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              spec.add_development_dependency "bundler", "~> 2.0"
         
     | 
| 
      
 41 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 10.0"
         
     | 
| 
      
 42 
     | 
    
         
            +
              spec.add_development_dependency "rspec", "~> 3.0"
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "dash_timeline_validator/adaptation_set"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "dash_timeline_validator/cli"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "dash_timeline_validator/file"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "dash_timeline_validator/log"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "dash_timeline_validator/options"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "dash_timeline_validator/period"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "dash_timeline_validator/report"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require "dash_timeline_validator/representation"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "dash_timeline_validator/segment"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "dash_timeline_validator/validator"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 13 
     | 
    
         
            +
              class Error < StandardError; end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 2 
     | 
    
         
            +
              class AdaptationSet
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.process(context, adaptation_set, index)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  as_result = {}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  as_result["name"] = "AdaptationSet-#{index}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(as_result, adaptation_set, "mimeType")
         
     | 
| 
      
 7 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(as_result, adaptation_set, "contentType")
         
     | 
| 
      
 8 
     | 
    
         
            +
                  all_representations = adaptation_set.nodes.select { |n| n.name == "Representation" }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  as_result["representations"] = all_representations.each_with_index.map do |representation, i|
         
     | 
| 
      
 11 
     | 
    
         
            +
                    DashTimelineValidator::Representation.process({root: context[:root], previous: as_result}, representation, i)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  as_result
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 4 
     | 
    
         
            +
              class CLI
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.error_exit(report)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  DashTimelineValidator::Log.info(report)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  exit(-1)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.main(manifest)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 12 
     | 
    
         
            +
                    FileUtils.mkdir_p DashTimelineValidator::Options::ANALYZER_FOLDER
         
     | 
| 
      
 13 
     | 
    
         
            +
                    DashTimelineValidator::Log.info("The manifest #{manifest} will be processed at #{DashTimelineValidator::Options::ANALYZER_FOLDER} folder.")
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    mpd_content = DashTimelineValidator::DashFile.fetch_file(manifest)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    DashTimelineValidator::Log.info(DashTimelineValidator::Validator.analyze(manifest, mpd_content))
         
     | 
| 
      
 18 
     | 
    
         
            +
                  rescue StandardError => e
         
     | 
| 
      
 19 
     | 
    
         
            +
                    DashTimelineValidator::Log.warn("There was an error: #{e.inspect}")
         
     | 
| 
      
 20 
     | 
    
         
            +
                    DashTimelineValidator::Log.warn(e.backtrace.join("\n\t"))
         
     | 
| 
      
 21 
     | 
    
         
            +
                    DashTimelineValidator::Log.warn("Removing the folder #{DashTimelineValidator::Options::ANALYZER_FOLDER}")
         
     | 
| 
      
 22 
     | 
    
         
            +
                    FileUtils.rm_rf DashTimelineValidator::Options::ANALYZER_FOLDER
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 4 
     | 
    
         
            +
              class DashFile
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.fetch_file(origin, file_path = Options::ANALYZER_MANIFEST_PATH)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  dirname = File.dirname(file_path)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  unless File.directory? dirname
         
     | 
| 
      
 8 
     | 
    
         
            +
                    FileUtils.mkdir_p(dirname)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  if uri? origin
         
     | 
| 
      
 12 
     | 
    
         
            +
                    download_and_save(origin, file_path)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  else
         
     | 
| 
      
 14 
     | 
    
         
            +
                    FileUtils.cp origin, file_path
         
     | 
| 
      
 15 
     | 
    
         
            +
                    File.read file_path
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def self.download_and_save(uri, path)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  content = Net::HTTP.get(URI.parse(uri))
         
     | 
| 
      
 21 
     | 
    
         
            +
                  File.write(path, content)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  content
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def self.uri?(string)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  uri = URI.parse(string)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  %w( http https ).include?(uri.scheme)
         
     | 
| 
      
 28 
     | 
    
         
            +
                rescue URI::BadURIError
         
     | 
| 
      
 29 
     | 
    
         
            +
                  false
         
     | 
| 
      
 30 
     | 
    
         
            +
                rescue URI::InvalidURIError
         
     | 
| 
      
 31 
     | 
    
         
            +
                  false
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "securerandom"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Options
         
     | 
| 
      
 5 
     | 
    
         
            +
                ACCEPTABLE_DRIFT = ENV["ACCEPTABLE_DRIFT"] || 2
         
     | 
| 
      
 6 
     | 
    
         
            +
                DEFAULT_PRESENTATION_DELAY = ENV["DEFAULT_PRESENTATION_DELAY"] || 10
         
     | 
| 
      
 7 
     | 
    
         
            +
                BUFFERED_SEGMENTS = ENV["BUFFERED_SEGMENTS"] || 2
         
     | 
| 
      
 8 
     | 
    
         
            +
                VERIFY_SEGMENTS_DURATION = ENV["VERIFY_SEGMENTS_DURATION"] || false
         
     | 
| 
      
 9 
     | 
    
         
            +
                ANALYZER_FOLDER = ENV["ANALYZER_FOLDER"] || "data/#{SecureRandom.uuid}".freeze
         
     | 
| 
      
 10 
     | 
    
         
            +
                ANALYZER_MANIFEST_PATH = ENV["ANALYZER_MANIFEST_PATH"] || "#{ANALYZER_FOLDER}/manifest.mpd".freeze
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Period
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.process(context, period, index)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  period_result = {}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  period_result["name"] = "Period-#{index}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(period_result, period, "start", 0, :duration_iso8601_to_i)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  all_adaptation_sets = period.nodes.select { |n| n.name == "AdaptationSet" }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  period_result["adaptation_sets"] = all_adaptation_sets.each_with_index.map do |adaptation_set, i|
         
     | 
| 
      
 11 
     | 
    
         
            +
                    DashTimelineValidator::AdaptationSet.process({root: context[:root], previous: period_result}, adaptation_set, i)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  period_result
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "iso8601"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Report
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.report_info(value)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  value
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.report_warn(value)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  "[WARN] #{value}"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def self.report_error(value)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  "[ERROR] #{value}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def self.fill_report(report, mpd_leaf, key_name, default_value = nil, parser_fn = :identity)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  if mpd_leaf.respond_to? key_name
         
     | 
| 
      
 19 
     | 
    
         
            +
                    report[key_name] = Report.report_info(self.send(parser_fn, mpd_leaf[key_name]))
         
     | 
| 
      
 20 
     | 
    
         
            +
                  elsif default_value
         
     | 
| 
      
 21 
     | 
    
         
            +
                    report[key_name] = Report.report_info(self.send(parser_fn, default_value))
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def self.fill_report_mandatory(report, mpd_leaf, key_name, parser_fn = :identity)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if !mpd_leaf.respond_to? key_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                    report[key_name] = report_error("Mandatory #{key_name} is missing")
         
     | 
| 
      
 28 
     | 
    
         
            +
                    error_exit(report)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  else
         
     | 
| 
      
 30 
     | 
    
         
            +
                    report[key_name] = Report.report_info(self.send(parser_fn, mpd_leaf[key_name]))
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def self.duration_iso8601_to_i(start)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  ISO8601::Duration.new(start).to_seconds
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def self.time_to_i(value)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  Time.parse(value).to_i
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def self.identity(value)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  value
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def self.to_i(value)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  value.to_i
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Representation
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.process(context, representation, index)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  representation_result = {}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  representation_result["name"] = "Representation-#{index}"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(representation_result, representation, "bandwidth")
         
     | 
| 
      
 8 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(representation_result, representation, "codecs")
         
     | 
| 
      
 9 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(representation_result, representation, "presentationTimeOffset", 0, :duration_iso8601_to_i)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  if representation.respond_to? "SegmentTemplate"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    segment_template = representation.SegmentTemplate
         
     | 
| 
      
 13 
     | 
    
         
            +
                    representation_result["SegmentTemplate"] = {}
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report_mandatory(representation_result["SegmentTemplate"], segment_template, "timescale", :to_i)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report_mandatory(representation_result["SegmentTemplate"], segment_template, "media")
         
     | 
| 
      
 17 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report(representation_result["SegmentTemplate"], segment_template, "initialization")
         
     | 
| 
      
 18 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report_mandatory(representation_result["SegmentTemplate"], segment_template, "startNumber")
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    if context[:root]["mpd"]["type"].eql? "dynamic"
         
     | 
| 
      
 21 
     | 
    
         
            +
                      report_edge_timeline_information = report_edge_timeline_information(context, representation_result, segment_template.SegmentTimeline.nodes)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      representation_result["SegmentTemplate"]["timeline"] = report_edge_timeline_information
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    if segment_template.respond_to? "SegmentTimeline"
         
     | 
| 
      
 26 
     | 
    
         
            +
                      DashTimelineValidator::Segment.process({root: context[:root], previous: representation_result["SegmentTemplate"]}, segment_template.SegmentTimeline.nodes)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  representation_result
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def self.report_edge_timeline_information(context, representation_result, ss)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  client_wallclock = context[:root]["client_wallclock"]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  ast = context[:root]["mpd"]["availabilityStartTime"]
         
     | 
| 
      
 36 
     | 
    
         
            +
                  timescale = representation_result["SegmentTemplate"]["timescale"]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  max_duration = ss.map { |s| s[:d].to_i }.max / timescale
         
     | 
| 
      
 38 
     | 
    
         
            +
                  min_buffer_time = context[:root]["mpd"]["minBufferTime"]
         
     | 
| 
      
 39 
     | 
    
         
            +
                  suggested_resentation_delay = context[:root]["mpd"]["suggestedPresentationDelay"]
         
     | 
| 
      
 40 
     | 
    
         
            +
                  default_presentation_delay = [DashTimelineValidator::Options::DEFAULT_PRESENTATION_DELAY, (min_buffer_time * 1.5)].max
         
     | 
| 
      
 41 
     | 
    
         
            +
                  timeline_delay = suggested_resentation_delay.nil? ? default_presentation_delay : suggested_resentation_delay
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # suggested streaming edge based on shaka's behavior
         
     | 
| 
      
 44 
     | 
    
         
            +
                  streaming_edge = client_wallclock - ast - DashTimelineValidator::Options::BUFFERED_SEGMENTS * max_duration - timeline_delay
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  last_segment = ss.last
         
     | 
| 
      
 47 
     | 
    
         
            +
                  last_available_time = (last_segment[:t].to_i + (last_segment[:d].to_i * last_segment[:r].to_i)) / timescale
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  if streaming_edge > last_available_time
         
     | 
| 
      
 50 
     | 
    
         
            +
                    report = DashTimelineValidator::Report.report_warn("Live edge is at #{streaming_edge}s but last segment in timeline starts at #{last_available_time}s")
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    report = DashTimelineValidator::Report.report_info("Live edge is at #{streaming_edge}s and last segment in timeline starts at #{last_available_time}s")
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  report
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Segment
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.process(context, ss)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  mpd_type = context[:root]["mpd"]["type"]
         
     | 
| 
      
 5 
     | 
    
         
            +
                  previous = context[:previous]
         
     | 
| 
      
 6 
     | 
    
         
            +
                  previous["S"] = []
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  ss.each_with_index do |s, index|
         
     | 
| 
      
 9 
     | 
    
         
            +
                    unless s.respond_to? "d"
         
     | 
| 
      
 10 
     | 
    
         
            +
                      previous["S"].push(DashTimelineValidator::Report.report_error("Segment (#{index + 1}) doen't have mandatory value for 'd'"))
         
     | 
| 
      
 11 
     | 
    
         
            +
                      error_exit(previous)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    if mpd_type.eql? "dynamic" and !s.respond_to? "t"
         
     | 
| 
      
 14 
     | 
    
         
            +
                      previous["S"].push(DashTimelineValidator::Report.report_warn("Segment <S d='#{s[:d]}' t='#{s[:t]}'/> doen't have a value for 't', it's necessary for MPD with 'dynamic' type"))
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  timeline_segments = ss.map { |s| {d: s.d.to_i, t: s.respond_to?("t") ? s.t.to_i : 0, r: s.respond_to?("r") ? s.r.to_i : 0} }
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  current_segment_number = context[:previous]["startNumber"].to_i
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  timeline_segments.each_with_index do |current_segment, index|
         
     | 
| 
      
 23 
     | 
    
         
            +
                    unless index.zero?
         
     | 
| 
      
 24 
     | 
    
         
            +
                      previous_segment = timeline_segments[index - 1]
         
     | 
| 
      
 25 
     | 
    
         
            +
                      current_segment_time = current_segment[:t]
         
     | 
| 
      
 26 
     | 
    
         
            +
                      expected_segment_time = (previous_segment[:t] + (previous_segment[:d]) * (1 + previous_segment[:r]))
         
     | 
| 
      
 27 
     | 
    
         
            +
                      drift = (expected_segment_time - current_segment_time).abs
         
     | 
| 
      
 28 
     | 
    
         
            +
                      if drift > DashTimelineValidator::Options::ACCEPTABLE_DRIFT
         
     | 
| 
      
 29 
     | 
    
         
            +
                        previous["S"].push(DashTimelineValidator::Report.report_warn("Timeline of <S d='#{current_segment[:d]}' t='#{current_segment[:t]}'/> was expected to be #{expected_segment_time}, but is #{current_segment_time} (drift = #{drift})"))
         
     | 
| 
      
 30 
     | 
    
         
            +
                      end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    if DashTimelineValidator::Options::VERIFY_SEGMENTS_DURATION
         
     | 
| 
      
 34 
     | 
    
         
            +
                      (current_segment[:r].to_i + 1).times do |i|
         
     | 
| 
      
 35 
     | 
    
         
            +
                        duration_report = check_segment_duration(context, current_segment, current_segment_number, i.zero?)
         
     | 
| 
      
 36 
     | 
    
         
            +
                        previous["S"].push(duration_report) if duration_report
         
     | 
| 
      
 37 
     | 
    
         
            +
                        current_segment_number += 1
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  previous.delete("S") if previous["S"].empty?
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def self.check_segment_duration(context, current_segment, current_segment_number, download_init = true)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  init = context[:previous]["initialization"]
         
     | 
| 
      
 46 
     | 
    
         
            +
                  media = context[:previous]["media"]
         
     | 
| 
      
 47 
     | 
    
         
            +
                  base_path = context[:root]["base_path"]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  init_path = "#{DashTimelineValidator::Options::ANALYZER_FOLDER}/#{init}"
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  DashTimelineValidator::DashFile.fetch_file("#{base_path}/#{init}", init_path) if download_init
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  segment_file = media.gsub("$Number$", current_segment_number.to_s)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  segment_path = "#{DashTimelineValidator::Options::ANALYZER_FOLDER}/#{segment_file}"
         
     | 
| 
      
 54 
     | 
    
         
            +
                  full_segment_path = "#{DashTimelineValidator::Options::ANALYZER_FOLDER}/#{segment_file}".gsub(".", "-complete.")
         
     | 
| 
      
 55 
     | 
    
         
            +
                  DashTimelineValidator::DashFile.fetch_file("#{base_path}/#{segment_file}", segment_path)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  `cat #{init_path} #{segment_path} > #{full_segment_path}`
         
     | 
| 
      
 58 
     | 
    
         
            +
                  duration = `mediainfo --Inform="General;%Duration%"  #{full_segment_path}`.to_i
         
     | 
| 
      
 59 
     | 
    
         
            +
                  File.delete segment_path
         
     | 
| 
      
 60 
     | 
    
         
            +
                  File.delete full_segment_path
         
     | 
| 
      
 61 
     | 
    
         
            +
                  mediainfo_duration = duration.to_f / 1000 * context[:previous]["timescale"].to_i
         
     | 
| 
      
 62 
     | 
    
         
            +
                  if (mediainfo_duration != current_segment[:d])
         
     | 
| 
      
 63 
     | 
    
         
            +
                    return DashTimelineValidator::Report.report_warn("Mediainfo shows different duration for #{segment_file} compared to the advertised segment timeline item (#{(mediainfo_duration - current_segment[:d]).abs})")
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "ox"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DashTimelineValidator
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Validator
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.analyze(manifest, mpd_content)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  report = {}
         
     | 
| 
      
 7 
     | 
    
         
            +
                  mpd = nil
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  if DashTimelineValidator::DashFile.uri? manifest
         
     | 
| 
      
 10 
     | 
    
         
            +
                    uri = URI(manifest)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    report["base_path"] = DashTimelineValidator::Report.report_info("#{uri.scheme}://#{uri.host}#{uri.path.split("/").reverse.drop(1).reverse.join("/")}")
         
     | 
| 
      
 12 
     | 
    
         
            +
                  else
         
     | 
| 
      
 13 
     | 
    
         
            +
                    report["base_path"] = DashTimelineValidator::Report.report_info(DashTimelineValidator::DashFile::ANALYZER_FOLDER)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 17 
     | 
    
         
            +
                    mpd = Ox.load(mpd_content)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  rescue
         
     | 
| 
      
 19 
     | 
    
         
            +
                    DashTimelineValidator::Log.error("Error while parsing #{manifest} it might be malformed (a non 2xx response)")
         
     | 
| 
      
 20 
     | 
    
         
            +
                    error_exit(report)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  report["client_wallclock"] = DashTimelineValidator::Report.report_info(client_wallclock(mpd))
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  report["mpd"] = {}
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report(report["mpd"], mpd.MPD, "type", "static")
         
     | 
| 
      
 28 
     | 
    
         
            +
                  DashTimelineValidator::Report.fill_report_mandatory(report["mpd"], mpd.MPD, "minBufferTime", :duration_iso8601_to_i)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  if report["mpd"]["type"] == "dynamic"
         
     | 
| 
      
 31 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report_mandatory(report["mpd"], mpd.MPD, "availabilityStartTime", :time_to_i)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    if mpd.MPD.respond_to? "suggestedPresentationDelay"
         
     | 
| 
      
 33 
     | 
    
         
            +
                      DashTimelineValidator::Report.fill_report(report["mpd"], mpd.MPD, "suggestedPresentationDelay", 0, :duration_iso8601_to_i)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  else
         
     | 
| 
      
 36 
     | 
    
         
            +
                    DashTimelineValidator::Report.fill_report(report["mpd"], mpd.MPD, "availabilityStartTime", Time.now.iso8601(0), :time_to_i)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  all_periods = mpd.MPD.nodes.select { |n| n.name == "Period" }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  report["mpd"]["periods"] = all_periods.each_with_index.map do |period, index|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    DashTimelineValidator::Period.process({root: report, previous: report["mpd"]}, period, index)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  report
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def self.client_wallclock(mpd)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  if mpd.MPD.respond_to? "UTCTiming"
         
     | 
| 
      
 49 
     | 
    
         
            +
                    if mpd.MPD.UTCTiming["schemeIdUri"].eql? "urn:mpeg:dash:utc:direct:2014"
         
     | 
| 
      
 50 
     | 
    
         
            +
                      raw_time = mpd.MPD.UTCTiming["value"]
         
     | 
| 
      
 51 
     | 
    
         
            +
                    elsif mpd.MPD.UTCTiming["schemeIdUri"].eql? "urn:mpeg:dash:utc:http-iso:2014"
         
     | 
| 
      
 52 
     | 
    
         
            +
                      raw_time = Net::HTTP.get(URI.parse(mpd.MPD.UTCTiming["value"]))
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  if raw_time.nil?
         
     | 
| 
      
 57 
     | 
    
         
            +
                    return DateTime.now.to_time.to_i
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  DateTime.parse(raw_time).to_time.to_i
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,155 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: dash_timeline_validator
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Ana Carolina Castro
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: exe
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-04-11 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: iso8601
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: 0.10.1
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: 0.10.1
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: ox
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: 2.9.0
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: 2.9.0
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: awesome_print
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: 1.8.0
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: 1.8.0
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '2.0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '2.0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 83 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 84 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 86 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 87 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 88 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 89 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 90 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 91 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 93 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 94 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 95 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 96 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 97 
     | 
    
         
            +
            description: MPEG-Dash Timeline Validator.
         
     | 
| 
      
 98 
     | 
    
         
            +
            email:
         
     | 
| 
      
 99 
     | 
    
         
            +
            - ana.castro@corp.globo.com
         
     | 
| 
      
 100 
     | 
    
         
            +
            executables:
         
     | 
| 
      
 101 
     | 
    
         
            +
            - dash_timeline_validator
         
     | 
| 
      
 102 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 103 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 104 
     | 
    
         
            +
            files:
         
     | 
| 
      
 105 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 106 
     | 
    
         
            +
            - ".rspec"
         
     | 
| 
      
 107 
     | 
    
         
            +
            - ".travis.yml"
         
     | 
| 
      
 108 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 109 
     | 
    
         
            +
            - Gemfile.lock
         
     | 
| 
      
 110 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 111 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 112 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 113 
     | 
    
         
            +
            - bin/console
         
     | 
| 
      
 114 
     | 
    
         
            +
            - bin/setup
         
     | 
| 
      
 115 
     | 
    
         
            +
            - dash_timeline_validator.gemspec
         
     | 
| 
      
 116 
     | 
    
         
            +
            - exe/dash_timeline_validator
         
     | 
| 
      
 117 
     | 
    
         
            +
            - lib/dash_timeline_validator.rb
         
     | 
| 
      
 118 
     | 
    
         
            +
            - lib/dash_timeline_validator/adaptation_set.rb
         
     | 
| 
      
 119 
     | 
    
         
            +
            - lib/dash_timeline_validator/cli.rb
         
     | 
| 
      
 120 
     | 
    
         
            +
            - lib/dash_timeline_validator/file.rb
         
     | 
| 
      
 121 
     | 
    
         
            +
            - lib/dash_timeline_validator/log.rb
         
     | 
| 
      
 122 
     | 
    
         
            +
            - lib/dash_timeline_validator/options.rb
         
     | 
| 
      
 123 
     | 
    
         
            +
            - lib/dash_timeline_validator/period.rb
         
     | 
| 
      
 124 
     | 
    
         
            +
            - lib/dash_timeline_validator/report.rb
         
     | 
| 
      
 125 
     | 
    
         
            +
            - lib/dash_timeline_validator/representation.rb
         
     | 
| 
      
 126 
     | 
    
         
            +
            - lib/dash_timeline_validator/segment.rb
         
     | 
| 
      
 127 
     | 
    
         
            +
            - lib/dash_timeline_validator/validator.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - lib/dash_timeline_validator/version.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            homepage: https://github.com/globocom/dash_timeline_validator
         
     | 
| 
      
 130 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 131 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 132 
     | 
    
         
            +
              homepage_uri: https://github.com/globocom/dash_timeline_validator
         
     | 
| 
      
 133 
     | 
    
         
            +
              source_code_uri: https://github.com/globocom/dash_timeline_validator
         
     | 
| 
      
 134 
     | 
    
         
            +
              changelog_uri: https://github.com/globocom/dash_timeline_validator
         
     | 
| 
      
 135 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 136 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 137 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 138 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 139 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 140 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 141 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 142 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 143 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 144 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 145 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 146 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 147 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 148 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 149 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 150 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 151 
     | 
    
         
            +
            rubygems_version: 2.7.3
         
     | 
| 
      
 152 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 153 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 154 
     | 
    
         
            +
            summary: MPEG-Dash Timeline Validator
         
     | 
| 
      
 155 
     | 
    
         
            +
            test_files: []
         
     |