Skip to content

Commit

Permalink
Fix & improve MediaInfo::Tracks::Attributes.standardize_to_millisecon…
Browse files Browse the repository at this point in the history
…ds. (#30)
  • Loading branch information
01max authored and NorseGaud committed Sep 4, 2018
1 parent 07e9a54 commit 743f038
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 51 deletions.
68 changes: 35 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
MediaInfo is a class wrapping [the mediainfo CLI](http://mediainfo.sourceforge.net).

## Installation

$ gem install mediainfo

## Usage

#### Parsing raw XML
Expand All @@ -16,28 +16,28 @@ MediaInfo is a class wrapping [the mediainfo CLI](http://mediainfo.sourceforge.n
media_info = MediaInfo.from('http://techslides.com/demos/sample-videos/small.mp4')

You can specify an alternate path for the MediaInfo Binary:

ENV['MEDIAINFO_PATH'] = "/opt/local/bin/mediainfo"

Once you have an MediaInfo object, you can start inspecting tracks:

media_info.track_types => ['general','video','audio']
media_info.track_types.count => 3
media_info.video? => true
media_info.image? => nil
media_info.image.filesize => MethodNotFound exception
When inspecting specific types of tracks, you have a couple general API options. The
first approach assumes one track of a given type, a common scenario in many video files,

When inspecting specific types of tracks, you have a couple general API options. The
first approach assumes one track of a given type, a common scenario in many video files,
for example:

media_info.video.count => 1
media_info.video.duration => 120 (seconds)

Sometimes you'll have more than one track of a given type:
- The first track type name, or any track type with <ID>1</ID> will not contain '1'


media_info.track_types => ['general','video','video2','audio','other','other2']
media_info.track_types.count => 5
media_info.video? => true
Expand All @@ -54,14 +54,14 @@ Sometimes you'll have more than one track of a given type:
media_info.video.encoded_date.class => Time
media_info.video2.duration.class => Integer
media_info.video.display_aspect_ratio.class => Float

- Any track attribute name with "date" and matching /\d-/ will be converted using Time.parse:


media_info.video.encoded_date => 2018-03-30 12:12:08 -0400
media_info.video.customdate => 2016-02-10 01:00:00 -0600
- .duration and .overall_duration will be returned as milliseconds AS LONG AS the Duration and Overall_Duration match one of the expected units:

- .duration and .overall_duration will be returned as milliseconds AS LONG AS the Duration and Overall_Duration match one of the expected units (each separated by a space or not):
- h (\<Duration>15h\</Duration>) (hour)
- hour (\<Duration>15hour\</Duration>)
- mn (\<Duration>15hour 6mn\</Duration>) (minute)
Expand All @@ -70,25 +70,27 @@ Sometimes you'll have more than one track of a given type:
- s (\<Duration>15hour 6min 59s\</Duration>) (second)
- sec (\<Duration>15hour 6min 59sec\</Duration>) (second)
- ms (\<Duration>15hour 6min 59sec 301ms\</Duration>) (milliseconds)
- in the form of a Float (as for iphone mov files)
- [Submit an issue to add more!](https://github.com/greatseth/mediainfo/issues)


media_info.video.duration => 9855000 (\<Duration>15s 164ms\</Duration>)
media_info.video.duration => 17196000 (\<Duration>36s 286ms\</Duration>)


media_info.video.duration => 15164 (\<Duration>15s 164ms\</Duration>)
media_info.video.duration => 36286 (\<Duration>36s 286ms\</Duration>)
media_info.video.duration => 123456 (\<Duration>123.456\</Duration>)

- We standardize the naming of several Attributes:
- You can review lib/attribute_standardization_rules.yml to see them all


media_info.video.bit_rate => nil (\<Bit_rate>41.2 Mbps\</Bit_rate>)
media_info.video.bitrate => "41.2 Mbps" (\<Bit_rate>41.2 Mbps\</Bit_rate>)
media_info.general.filesize => "11.5 MiB" (\<File_size>11.5 MiB\</File_size>


In order to support all possible MediaInfo variations, you may see the following situation:

media_info.track_types => ['general','video','video5','audio','other','other2']

The track type media_info.video5 is available, but no video2, 3, and 4. This is because the MediaInfo from the video has:

<track type="Video">
Expand All @@ -99,7 +101,7 @@ The track type media_info.video5 is available, but no video2, 3, and 4. This is
...

*The ID will take priority for labeling.* Else if no ID exists, you'll see consecutive numbering for duplicate tracks in the Media.

Any second level attributes are also available:

MediaInfo.from('~/Desktop/test.mov').general.extra
Expand All @@ -110,17 +112,17 @@ Any second level attributes are also available:
@com_apple_quicktime_model=0,
@com_apple_quicktime_software=11.2>

REXML is used as the XML parser by default. If you'd like, you can
REXML is used as the XML parser by default. If you'd like, you can
configure Mediainfo to use Nokogiri instead:

* define the `MEDIAINFO_XML_PARSER` environment variable to be the
name of the parser as you'd pass to a :gem or :require call.
* define the `MEDIAINFO_XML_PARSER` environment variable to be the
name of the parser as you'd pass to a :gem or :require call.

e.g. `export MEDIAINFO_XML_PARSER=nokogiri`
Once you've got an instance setup, you can call numerous methods to get
a variety of information about a file. Some attributes may be present
for some files where others are not, but any supported attribute

Once you've got an instance setup, you can call numerous methods to get
a variety of information about a file. Some attributes may be present
for some files where others are not, but any supported attribute
should at least return `nil`.

## Requirements
Expand All @@ -136,4 +138,4 @@ should at least return `nil`.
* Ned Campion - [http://github.com/nedcampion](http://github.com/nedcampion)
* Daniel Jagszent - [http://github.com/d--j](http://github.com/d--j)
* Robert Mrasek - [http://github.com/derobo](http://github.com/derobo)
* Nathan Pierce - [http://github.com/NorseGaud](http://github.com/NorseGaud)
* Nathan Pierce - [http://github.com/NorseGaud](http://github.com/NorseGaud)
36 changes: 20 additions & 16 deletions lib/mediainfo/tracks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,23 +119,27 @@ def self.sanitize_element_value(param)
end

def self.standardize_to_milliseconds(value)
# TODO iphone video has a float as the duration
# UPDATE THE README IF YOU'RE CHANGING THIS
milliseconds = 0
value.scan(/\d+\s?\w+/).each do |chunk|
case chunk
when /\d+\s?h/ then milliseconds += chunk.to_i * 60 * 60 * 1000
when /\d+\s?hour/ then milliseconds += chunk.to_i * 60 * 60 * 1000
when /\d+\s?m/ then milliseconds += chunk.to_i * 60 * 1000
when /\d+\s?mn/ then milliseconds += chunk.to_i * 60 * 1000
when /\d+\s?min/ then milliseconds += chunk.to_i * 60 * 1000
when /\d+\s?s/ then milliseconds += chunk.to_i * 1000
when /\d+\s?sec/ then milliseconds += chunk.to_i * 1000
when /\d+\s?ms/ then milliseconds += chunk.to_i
end
return standardize_float_to_milliseconds(value.to_f) if value.to_f.to_s == value.to_s
return standardize_string_to_milliseconds(value)
value
end

def self.standardize_string_to_milliseconds(v, base_msec = 0)
v.scan(/\d+\s?\D+/).each do |chunk|
base_msec += case chunk
when /\d+\s?ms/ then chunk.to_i
when /\d+\s?s(ec)?/ then chunk.to_i * 1000
when /\d+\s?m(i?n)?/ then chunk.to_i * 60 * 1000
when /\d+\s?h(our)?/ then chunk.to_i * 60 * 60 * 1000
end.to_i
end
milliseconds = value if milliseconds == 0 # We don't raise anymore. It's much better for the gem to work, returning the original MediaInfo attribute, than raise.
return milliseconds
# We don't raise anymore. It's much better for the gem to work,
# returning the original MediaInfo attribute, than raise.
base_msec == 0 ? v : base_msec
end

def self.standardize_float_to_milliseconds(v)
(v*1000).to_i
end

end
Expand Down
4 changes: 2 additions & 2 deletions spec/mediainfo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@
# REXML
# TODO (see tracks.rb under standardize_to_milliseconds) expect(MediaInfo.obtain(::File.open('./spec/fixtures/xml/iphone6+_video.mov.xml').read).video.duration).to be_a(Integer)
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/AwayWeGo_24fps.mov.xml').read).video.duration).to be_a(Integer)
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/multiple_streams_no_stream_id_three_video.xml').read).video100.duration).to eq(10204000)
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/multiple_streams_no_stream_id_three_video.xml').read).video100.duration).to eq(4170)
# NOKOGIRI
ENV['MEDIAINFO_XML_PARSER'] = 'nokogiri'
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/hats.3gp.xml').read).video.duration).to be_a(Integer)
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/vimeo.57652.avi.xml').read).video.duration).to eq(9855000)
expect(MediaInfo.from(::File.open('./spec/fixtures/xml/vimeo.57652.avi.xml').read).video.duration).to eq(15164)
ENV['MEDIAINFO_XML_PARSER'] = nil
end

Expand Down

0 comments on commit 743f038

Please sign in to comment.