Skip to content

Commit

Permalink
First stab at this. Some specs that run. Still need to rubify it a bi…
Browse files Browse the repository at this point in the history
…t more. No real support for multiple streams per file yet on the Rubyisms.
  • Loading branch information
hackerdude committed Jul 15, 2010
0 parents commit 4c6c9d9
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'rubygems'
require 'rake'
require 'echoe'

Echoe.new("mediainfo-ruby", "0.1.4") do |p|
p.description = "MediaInfo Ruby Bridge. Call MediaInfo lib directly"
p.url = "http://github.com/hackerdude/mediainfo-ruby"
p.author = "David Martinez"
p.ignore_pattern = ["tmp/*", "script/*", "pkg/*"]
p.development_dependencies = [] # TODO How to do native dependencies?
end


Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each{|ext| load ext }

Binary file added ext/mediainfo_ruby/.mediainfo_ruby.cpp.swp
Binary file not shown.
39 changes: 39 additions & 0 deletions ext/mediainfo_ruby/extconf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'mkmf-rice'

#require 'ruby-debug'
#Debugger.start

if RUBY_PLATFORM == "universal-darwin10.0"
# TODO Set the archflags to -arch x86_64 ONLY if it's a 64-bit snow leopard machine.
ENV['ARCHFLAGS'] = "-arch x86_64"
#$CFLAGS.sub!("-arch x86_64", "")
end

MEDIAINFO_HEADER_FILE="MediaInfoDLL/MediaInfoDLL_Static.h"

HEADER_DIRS = [
"#{ENV['MEDIAINFO_DIR']}/Source",
'/usr/local/src/mediainfolib/Source',
'/opt/local/include',
'/usr/local/include',
'/usr/include'
]
HEADER_DIRS.shift if ENV['MEDIAINFO_DIR'].nil?

LIB_DIRS = [
"#{ENV['MEDIAINFO_DIR']}/Source",
'/opt/local/lib',
'/usr/local/lib',
'/usr/local', # For whatever reason, building mediainfo on Mac OSX put it here.
'/usr/lib'
]
LIB_DIRS.shift if ENV['MEDIAINFO_DIR'].nil?
dir_config("mediainfo", HEADER_DIRS, LIB_DIRS)
have_library("stdc++")
have_header "MediaInfoDLL/MediaInfoDLL_Static.h"
have_library("mediainfo", "MediaInfo_New", ['string.h', MEDIAINFO_HEADER_FILE])

create_makefile('mediainfo_ruby')

65 changes: 65 additions & 0 deletions ext/mediainfo_ruby/mediainfo_ruby.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

#include "rice/Class.hpp"
#include "rice/Data_Type.hpp"
#include "rice/Constructor.hpp"
#include "rice/Enum.hpp"
#include "rice/Module.hpp"

#include <string.h>
#include <MediaInfoDLL/MediaInfoDLL.h>
#define MediaInfoNameSpace MediaInfoDLL

using namespace Rice;
using namespace MediaInfoNameSpace;

extern "C" void Init_mediainfo_ruby()
{
//printf( "Dude!\n");
//define_module("MediaInfoLib").
define_enum<stream_t>("MediaInfoLib_StreamKind")
.define_value("General", Stream_General)
.define_value("Video", Stream_Video)
.define_value("Audio", Stream_Audio)
.define_value("Text", Stream_Text)
.define_value("Chapters", Stream_Chapters)
.define_value("Image", Stream_Image)
.define_value("Menu", Stream_Menu)
.define_value("Max", Stream_Max)
;

//define_module("MediaInfo").
define_enum<info_t>("MediaInfoLib_InfoKind")
.define_value("Name", Info_Name)
.define_value("Text", Info_Text)
.define_value("Measure", Info_Measure)
.define_value("Options", Info_Options)
.define_value("Name_Text", Info_Name_Text)
.define_value("Measure_Text", Info_Measure_Text)
.define_value("Info", Info_Info)
.define_value("HowTo", Info_HowTo)
//.define_value("Domain", Info_Domain)
.define_value("Max", Info_Max)
;
//define_class<File__Analyze>("File__Analyze")
//;
typedef std::string(MediaInfo::*get_info)(stream_t,size_t,size_t,info_t);
typedef std::string(MediaInfo::*get_info_somewhere)(stream_t, size_t,const std::string,info_t,info_t);
typedef std::string(MediaInfo::*get_info_string)(stream_t StreamKind, size_t StreamNumber, const std::string &Parameter, info_t InfoKind, info_t SearchKind);


define_module("MediaInfoLib").
define_class<MediaInfo>("MediaInfo")
.define_constructor(Constructor<MediaInfo>())
.define_method("_inform", &MediaInfo::Inform)
.define_method("option", &MediaInfo::Option)
.define_method("open", &MediaInfo::Open)
.define_method("close", &MediaInfo::Close)
.define_method("state_get", &MediaInfo::State_Get)
.define_method("count_get", &MediaInfo::Count_Get)
.define_method("get", get_info(&MediaInfo::Get))
// TODO Enabling this breaks with "address of overloaded function with no contextual type information".. Signature doesn't match
.define_method("get_value", get_info_string(&MediaInfo::Get))
//.define_method("_count_get", &MediaInfo::Count_Get)
;
//printf( "OK so at least MediaInfo is initialized now\n");
}
107 changes: 107 additions & 0 deletions lib/mediainfo-ruby.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Load the C++ library.
$:.unshift "#{File.dirname(__FILE__)}/../ext/mediainfo_ruby/"

puts "Loading mediainfo"
require "mediainfo_ruby"

module MediaInfoRubyisms_Streams
# A symbol map to translate from the Rubyisms we use on mediainfo-ruby
# to the constants libmediainfo uses.
StreamKindSymbolsMap = {
:general=>MediaInfoLib_StreamKind::General,
:video=>MediaInfoLib_StreamKind::Video,
:audio=>MediaInfoLib_StreamKind::Audio,
:text=>MediaInfoLib_StreamKind::Text,
:chapters=>MediaInfoLib_StreamKind::Chapters,
:image=>MediaInfoLib_StreamKind::Image,
:menu=>MediaInfoLib_StreamKind::Menu,
:max=>MediaInfoLib_StreamKind::Max
}

# Call inform and remove the DOS-linefeeds. Useful for quick printout
# of a bunch of media information
def inform
self._inform.split("\r")
end

# Returns how many streams in total this file has.
def streams; self.count_get(MediaInfoLib_StreamKind::General, -1) ; end

# Returns how many streams are audio streams
def audio_streams ; self.count_get(MediaInfoLib_StreamKind::Audio, -1) ; end

# Returns how many streams are video streams
def video_streams ; self.count_get(MediaInfoLib_StreamKind::Video, -1); end

# Returns how many streams are chapter streams
def chapter_streams ; self.count_get(MediaInfoLib_StreamKind::Chapters, -1); end

# Returns how many streams are image streams
def image_streams ; self.count_get(MediaInfoLib_StreamKind::Image, -1); end

# Returns how many streams are menu streams
def menu_streams ; self.count_get(MediaInfoLib_StreamKind::Menu, -1); end

# Returns a map of all the possible option definitions,
# where the key is the option we can ask for and the
# value is the help for that option.
# By default, anything marked as deprecated in the underlying
# library is removed.
def option_definitions(remove_deprecated=true)
option_map = {}
current = :general
switching = true
current_map = option_map[:general]
option_defs = self.option("Info_Parameters_CSV", "").split("\r").each{|row|
if row.strip == ""
switching = true
else
kv = row.split(";")
if kv.length == 1 && switching
topic = kv[0].downcase.to_sym
current_map = option_map[topic]
if current_map.nil?
option_map[topic] = current_map = {}
end
switching = false
else
current_map[kv[0]] = kv[1] unless remove_deprecated && kv[1].nil? ? false : kv[1].include?("Deprecated")
end
end
}
option_map
end

# It introspects a video. This means returning a map of all the
# values for a definition. By default empty values are not returned.
# Send with true to return empty values
def introspect(empty_values=false,include_inform=false)
results = {}
self.option_definitions.each{|topic, topic_parameters|
kind_constant = StreamKindSymbolsMap[topic]
if ! kind_constant.nil?
results[topic] = {}
topic_parameters.each{|key, value|
# TODO Do this for multiple streams and whatnot?
#debugger if topic == :video && self.video_streams > 0
value = self.get_value(kind_constant, 0, key, MediaInfoLib_InfoKind::Text, MediaInfoLib_InfoKind::Name)

if empty_values == true || value.length > 0
results[topic][key] = value
end
if key == "Inform"
results[topic].delete(key) if ! include_inform
end
# self.get(kind_constant, 1,0, key) # Something like this
}
end
}
results
end

end

class MediaInfoLib::MediaInfo
include(MediaInfoRubyisms_Streams)
end

1 change: 1 addition & 0 deletions spec/fixtures/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Put some videos here, then run the spec to try it out!
61 changes: 61 additions & 0 deletions spec/mediainfo_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require "#{File.dirname(__FILE__)}/../lib/mediainfo-ruby"
describe MediaInfoLib::MediaInfo do
VIDEO_FIXTURES = "#{File.dirname(__FILE__)}/fixtures"

before(:all) do
@video_files = Dir.new(VIDEO_FIXTURES).collect{|f|
f unless f[0..0] == "." || f.include?(".swf") || f.include?("flv")
}.compact
if @video_files.length == 0
puts "Please put some video files on spec/fixtures to test"
end
end
context "When getting video files" do
before(:each) do
@mediainfo = MediaInfoLib::MediaInfo.new
end
after(:each) do
@mediainfo.close
end
it "Can open local files" do
@video_files.each{|video|
@mediainfo.open("#{VIDEO_FIXTURES}/#{video}").should > 0
@mediainfo.inform.length.should > 0
}
end
it "Can get info from files" do
@video_files.each{|video|
@mediainfo.open("#{VIDEO_FIXTURES}/#{video}").should > 0
@mediainfo.streams.should > 0
@mediainfo.streams.should < 1000
#@mediainfo.get(MediaInfoLib_StreamKind::General,1,0,MediaInfoLib_InfoKind::Name).should_not be_nil
}
end
it "Can get the option definitions for a file" do
definitions = @mediainfo.option_definitions
[:general, :audio, :video, :text, :chapters, :menu, :text, :image].each{|topic|
# All these topics should be there
definitions.keys.should include(topic)
# All these topics should have more than one item
definitions[topic].keys.length.should > 0
}
#pp definitions
end
it "Can get the Media Info values for a file" do
@video_files.each{|video|
@mediainfo.open("#{VIDEO_FIXTURES}/#{video}").should > 0
values = @mediainfo.introspect
#puts "Streams for #{video}: Video:#{@mediainfo.video_streams} Audio:#{@mediainfo.audio_streams} Image:#{@mediainfo.image_streams}"
if @mediainfo.video_streams > 0
[:general, :audio, :video, :text, :chapters, :menu, :text, :image].each{|topic| values.should include(topic)}
# TODO Spot check some topics.
values[:general].keys.length.should > 0
values[:general]["CodecID"].should_not be_nil
values[:general]["CodecID"].should_not include("TODO")
#pp values
end
}
end
end

end

0 comments on commit 4c6c9d9

Please sign in to comment.