Class: MediaInfo::Tracks

Inherits:
Object
  • Object
show all
Defined in:
lib/mediainfo/tracks.rb

Defined Under Namespace

Classes: Attributes

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input = nil) ⇒ Tracks

Returns a new instance of Tracks.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/mediainfo/tracks.rb', line 13

def initialize(input = nil)
  if input && input.include?('<?xml')
    @xml = input.gsub(/(\n|.)*(\<\?xml)/,'<?xml')
    @track_types = []
    @attribute_standardization_rules = YAML.load_file("#{Gem::Specification.find_by_name('mediainfo').gem_dir}/lib/attribute_standardization_rules.yml")
    # Populate Streams
    case MediaInfo.xml_parser
    when 'nokogiri'
      converted_xml = ::Nokogiri::XML(self.xml)
      converted_xml.css('//track').each { |track| # Have to use .css here due to iphone6 MediaInfo structure
        track_elements = Attributes.new(track.children.select{ |n| n.is_a? ::Nokogiri::XML::Element }.map{ |parameter|
          parameter.name = standardize_element_name(parameter.name) # Turn various element names into standardized versions (Bit_rate to Bitrate)
          if parameter.text.include?("\n") # if it has children (extra in iphone6+_video.mov.xml)
            [parameter.name, parameter.children.select { |n| n.is_a? ::Nokogiri::XML::Element }.map{ |parameter| [parameter.name, parameter.text]}]
          else
            [parameter.name, parameter.text]
          end
        })
        track_type = sanitize_track_type(@track_types,track.attributes.map{ |k,v| { :name => v.name, :value => v.value } },track.children.css('ID').map{ |el| el.text })
        @track_types << track_type
        MediaInfo.set_singleton_method(self,track_type,track_elements)
      }
    else # DEFAULT REXML
      converted_xml = ::REXML::Document.new(self.xml)
      converted_xml.elements.each('//track') { |track|
        track_elements = Attributes.new(track.children.select { |n| n.is_a? ::REXML::Element }.map{ |parameter|
          parameter.name = standardize_element_name(parameter.name)
          if parameter.text.include?("\n") # if it has children (extra in iphone6+_video.mov.xml)
            [parameter.name, parameter.children.select { |n| n.is_a? ::REXML::Element }.map{ |parameter| [parameter.name, parameter.text]}]
          else
            [parameter.name, parameter.text]
          end
        })
        track_type = sanitize_track_type(@track_types,track.attributes.map{ |attr| { :name => attr[0], :value => attr[1] } },track.elements.detect{|el| el.name == 'id' }.to_a)
        @track_types << track_type
        MediaInfo.set_singleton_method(self,track_type,track_elements)
      }
    end

    # Add {type}?
    @track_types.each{ |track_type|
      define_singleton_method("#{track_type}?"){ # Can't use set_singleton_method due to ?
        self.track_types.include?(__method__.to_s.gsub('?',''))
      }
    }
    # Add {type}.count singleton_method
    @track_types.each{ |track_type|
      MediaInfo.set_singleton_method(self.instance_variable_get("@#{track_type}"),'count',@track_types.grep(/#{track_type}/).count)
    }

  else
    raise ArgumentError, 'Input must be raw XML.'
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Needed so that .image?, when there is no Image track, doesn’t throw NoMethodError



7
8
9
# File 'lib/mediainfo/tracks.rb', line 7

def method_missing( name, *args )
  nil # We use nil here instead of false as nil should be understood by the client/requester as false. We might not want to specifically return false for other missing methods
end

Instance Attribute Details

#attribute_standardization_rulesObject (readonly)

Returns the value of attribute attribute_standardization_rules.



11
12
13
# File 'lib/mediainfo/tracks.rb', line 11

def attribute_standardization_rules
  @attribute_standardization_rules
end

#track_typesObject (readonly)

Returns the value of attribute track_types.



11
12
13
# File 'lib/mediainfo/tracks.rb', line 11

def track_types
  @track_types
end

#xmlObject (readonly)

Returns the value of attribute xml.



11
12
13
# File 'lib/mediainfo/tracks.rb', line 11

def xml
  @xml
end

Instance Method Details

#sanitize_track_type(track_types, track_attributes, track_id) ⇒ Object

Used for handling duplicate track types with differing streamid, etc Takes an array of attributes and returns the track_name Parameters must meet the following structure: TRACK_TYPES: [‘video’,‘video2’,‘text’] or [] if nothing created yet TRACK_ATTRIBUTES: [{:name=>“type”, :value=>“Text” }] or [] if not found TRACK_ID: [“1”] or [] if not found



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/mediainfo/tracks.rb', line 151

def sanitize_track_type(track_types,track_attributes,track_id)
  raise("Unable to sanitize a track type due to missing 'type' attribute in on of the elements: \n #{track_attributes}") if (type_attr_value = track_attributes.detect{ |attr| attr[:name] == 'type' }[:value]).nil?
  if (streamid = track_attributes.detect{ |attr| attr[:name] == 'streamid' || attr[:name] == 'typeorder' }).nil? # No StreamId, however, ensuring that if the streamid is there we use it ## We must still manually specify the id attr until https://sourceforge.net/p/mediainfo/discussion/297610/thread/f17a0cf5/ is answered
    ## Even if no streamid we need to check for duplicate track names and append an integer. ONLY WORKS IF DUPLICATE TRACKS ARE CONSECUTIVE
    if track_types.include?(type_attr_value.downcase)
      if !track_id.nil? && !track_id.empty? && track_id.first.to_s.to_i > 1 ## If the track has an ID child, and it's an integer above 1 (if it's a string, to_i returns 0) (if to_i returns > 1 so we can match id convention of video vs video1; see code below this section), use that
        type = "#{type_attr_value}#{track_id.first}"
      else
        type = "#{type_attr_value}#{track_types.grep(/#{type_attr_value.downcase}/).count + 1}"
      end
    else
      type = type_attr_value
    end
  else
    # For anything with a streamid of 1, ignore it. This is due to the logic of non-streamid duplicates not appending an integer for the first occurrence. We want to be consistent.
    ## We use _ to separate the streamid so we can do easier matching for non-streamid duplicates
    type = streamid[:value] == '1' ? type_attr_value : "#{type_attr_value}#{streamid[:value]}"
  end
  return type.downcase
end

#standardize_element_name(name) ⇒ Object

Standardize our Element Names Relies on valid YAML in lib/attribute_standardization_rules.yml



70
71
72
# File 'lib/mediainfo/tracks.rb', line 70

def standardize_element_name(name)
  self.attribute_standardization_rules[name].nil? ? name : self.attribute_standardization_rules[name]
end