ffruby 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +504 -0
- data/README.rdoc +44 -0
- data/Rakefile +40 -139
- data/VERSION +1 -0
- data/ext/ffruby/extconf.rb +20 -7
- data/ext/ffruby/ffruby.c +41 -6
- data/ext/ffruby/ffruby.h +34 -0
- data/ext/ffruby/ffrubyfile.c +56 -31
- data/ext/ffruby/ffrubystream.c +78 -52
- metadata +59 -46
- data/README +0 -1
- data/lib/ffruby/version.rb +0 -9
data/README.rdoc
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
= FFruby
|
2
|
+
|
3
|
+
FFruby is a Ruby interface to FFmpeg's libavformat and libavcodec. It allows you to query metadata from a wide variety of media files through some simple classes. FFmpeg's libraries are required and also the development headers if building.
|
4
|
+
|
5
|
+
== FAQ
|
6
|
+
|
7
|
+
=== Where do I go for support and contributions?
|
8
|
+
|
9
|
+
We are hosted by RubyForge at http://rubyforge.org/projects/ffruby.
|
10
|
+
|
11
|
+
=== Where do I get the latest version?
|
12
|
+
|
13
|
+
It should be available through RubyGems as ffruby. Failing that, try RubyForge.
|
14
|
+
|
15
|
+
=== What about transcoding?
|
16
|
+
|
17
|
+
I still start FFmpeg through a subshell when I need to transcode something. There is little to be gained from doing this within Ruby itself. Other than requiring a fair amount of work, one major disadvantage is that if FFmpeg segfaults (which it has been known to do), it will bring the entire Ruby process down with it, which is probably something you want to avoid.
|
18
|
+
|
19
|
+
=== So what is this good for?
|
20
|
+
|
21
|
+
Being able to reliably read the source file's metadata is very important in deciding how it should be transcoded, or whether it even needs to be transcoded at all. This is not something you want to rely on a subshell for as that would involve awkward parsing of FFmpeg's output, which does change between versions.
|
22
|
+
|
23
|
+
== Changes
|
24
|
+
|
25
|
+
=== 0.2.0 (2010/11/24)
|
26
|
+
|
27
|
+
- Reworked class structure under common FFruby module.
|
28
|
+
- Compatibility with old and new FFmpeg versions.
|
29
|
+
- Methods to query supported formats and codecs.
|
30
|
+
- Safer memory handling.
|
31
|
+
- RDoc documentation.
|
32
|
+
- Repackaged using Jeweler.
|
33
|
+
|
34
|
+
=== 0.1 (2007/07/26), 0.0.1 (2008/01/11)
|
35
|
+
|
36
|
+
- More or less the same original version. Latter was the initial gem release.
|
37
|
+
|
38
|
+
== Authors
|
39
|
+
|
40
|
+
- James Le Cuirot <chewi@aura-online.co.uk>
|
41
|
+
|
42
|
+
== Copyright
|
43
|
+
|
44
|
+
Copyright (c) 2007-2010 James Le Cuirot. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,147 +1,48 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
]
|
22
|
-
RDOC_OPTS = ["--quiet", "--title", "FFruby Reference", "--main", "README", "--inline-source"]
|
23
|
-
|
24
|
-
@config_file = "~/.rubyforge/user-config.yml"
|
25
|
-
@config = nil
|
26
|
-
def rubyforge_username
|
27
|
-
unless @config
|
28
|
-
begin
|
29
|
-
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
30
|
-
rescue
|
31
|
-
puts <<-EOS
|
32
|
-
ERROR: No rubyforge config file found: #{@config_file}"
|
33
|
-
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
34
|
-
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
35
|
-
EOS
|
36
|
-
exit
|
37
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
RDOC_FILES = [ "README.rdoc", "ext/ffruby/ffruby{file,stream,}.c" ]
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "ffruby"
|
10
|
+
gem.version = File.read('VERSION')
|
11
|
+
gem.license = "LGPL-2.1"
|
12
|
+
gem.author = "James Le Cuirot"
|
13
|
+
gem.email = "chewi@aura-online.co.uk"
|
14
|
+
gem.rubyforge_project = "ffruby"
|
15
|
+
gem.homepage = "http://rubyforge.org/projects/ffruby/"
|
16
|
+
gem.summary = "A Ruby interface to FFmpeg's libavformat and libavcodec."
|
17
|
+
gem.description = "A Ruby interface to FFmpeg's libavformat and libavcodec. It allows you to query metadata from a wide variety of media files through some simple classes."
|
18
|
+
gem.requirements = "FFmpeg libraries and also development headers if building."
|
19
|
+
gem.files = RDOC_FILES + [ "LICENSE", "Rakefile", "VERSION", "ext/ffruby/{extconf.rb,ffruby.h}" ]
|
20
|
+
gem.extra_rdoc_files = RDOC_FILES
|
38
21
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
task :default => [:compile, :test]
|
44
|
-
|
45
|
-
desc "Compiles all extensions"
|
46
|
-
task :compile => [:ffruby] do
|
47
|
-
if Dir.glob(File.join("lib","ffruby*.*")).length == 0
|
48
|
-
STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
49
|
-
STDERR.puts "Gem actually failed to build. Your system is"
|
50
|
-
STDERR.puts "NOT configured properly to build ffruby."
|
51
|
-
STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
52
|
-
exit(1)
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
24
|
+
rubyforge.doc_task = "rdoc"
|
25
|
+
rubyforge.remote_doc_path = ""
|
53
26
|
end
|
27
|
+
rescue LoadError
|
28
|
+
puts "To prepare a gem, please install the jeweler gem."
|
54
29
|
end
|
55
30
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
desc "Run all the tests"
|
63
|
-
Rake::TestTask.new do | test_task |
|
64
|
-
test_task.libs << "test"
|
65
|
-
test_task.test_files = FileList["test/test_*.rb"]
|
66
|
-
test_task.verbose = true
|
67
|
-
end
|
68
|
-
|
69
|
-
Rake::RDocTask.new do | rdoc |
|
70
|
-
rdoc.rdoc_dir = "doc/rdoc"
|
71
|
-
rdoc.options += RDOC_OPTS
|
72
|
-
rdoc.main = "README"
|
73
|
-
rdoc.rdoc_files.add ["README", "lib/**/*.rb"]
|
74
|
-
end
|
75
|
-
|
76
|
-
spec =
|
77
|
-
Gem::Specification.new do | specification |
|
78
|
-
specification.name = GEM_NAME
|
79
|
-
specification.version = GEM_VERSION
|
80
|
-
specification.platform = Gem::Platform::RUBY
|
81
|
-
specification.has_rdoc = true
|
82
|
-
specification.rdoc_options += RDOC_OPTS
|
83
|
-
specification.extra_rdoc_files = ["README"]
|
84
|
-
specification.summary = "a library that does something with media files!"
|
85
|
-
specification.description = specification.summary
|
86
|
-
specification.author = "ffruby: James Le Cuirot, gem: Wayne E. Seguin"
|
87
|
-
specification.email = "wayneeseguin at gmail dot com"
|
88
|
-
specification.homepage = "ffruby.rubyforge.org"
|
89
|
-
|
90
|
-
specification.files = %w(README Rakefile) +
|
91
|
-
Dir.glob("{bin,doc,test,lib,extras}/**/*") +
|
92
|
-
Dir.glob("ext/**/*.{h,c,rb,rl}") +
|
93
|
-
%w[ext/ffruby/ffruby.c] # needed because it's generated later
|
94
|
-
|
95
|
-
specification.require_path = "lib"
|
96
|
-
specification.extensions = FileList["ext/**/extconf.rb"].to_a
|
97
|
-
specification.bindir = "bin"
|
98
|
-
end
|
99
|
-
|
100
|
-
Rake::GemPackageTask.new(spec) do | package |
|
101
|
-
package.need_tar = true
|
102
|
-
package.gem_spec = spec
|
103
|
-
end
|
104
|
-
|
105
|
-
extension = "ffruby"
|
106
|
-
ext = "ext/ffruby"
|
107
|
-
ext_so = "#{ext}/#{extension}.#{Config::CONFIG["DLEXT"]}"
|
108
|
-
ext_files = FileList[
|
109
|
-
"#{ext}/*.c",
|
110
|
-
"#{ext}/*.h",
|
111
|
-
"#{ext}/*.rl",
|
112
|
-
"#{ext}/extconf.rb",
|
113
|
-
"#{ext}/Makefile",
|
114
|
-
"lib"
|
115
|
-
]
|
116
|
-
|
117
|
-
task "lib" do
|
118
|
-
directory "lib"
|
119
|
-
end
|
120
|
-
|
121
|
-
desc "Builds just the #{extension} extension"
|
122
|
-
task extension.to_sym => ["#{ext}/Makefile", ext_so ]
|
123
|
-
|
124
|
-
file "#{ext}/Makefile" => ["#{ext}/extconf.rb"] do
|
125
|
-
#Dir.chdir(ext) do
|
126
|
-
if `uname.a`.match(/Darwin Kernel Version 9\.0\.0:.*i386/)
|
127
|
-
ENV["ARCHFLAGS"] = "-arch i386"
|
128
|
-
end
|
129
|
-
ruby "extconf.rb"
|
130
|
-
#end
|
131
|
-
end
|
132
|
-
|
133
|
-
file ext_so => ext_files do
|
134
|
-
Dir.chdir(ext) do
|
135
|
-
sh(PLATFORM =~ /win32/ ? "nmake" : "make")
|
31
|
+
begin
|
32
|
+
require 'rake/rdoctask'
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
rdoc.rdoc_dir = 'rdoc'
|
35
|
+
rdoc.title = "FFruby " + File.read('VERSION')
|
36
|
+
rdoc.rdoc_files.include *RDOC_FILES
|
136
37
|
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
task :install do
|
141
|
-
sh %{rake package}
|
142
|
-
sh %{sudo gem install pkg/#{GEM_NAME}-#{GEM_VERSION}}
|
38
|
+
rescue LoadError
|
39
|
+
puts "To build the documentation, please install the rdoc gem."
|
143
40
|
end
|
144
41
|
|
145
|
-
|
146
|
-
|
42
|
+
begin
|
43
|
+
require 'rake/extensiontask'
|
44
|
+
Rake::ExtensionTask.new('ffruby')
|
45
|
+
task :default => :compile
|
46
|
+
rescue LoadError
|
47
|
+
puts "To build the library, please install the rake-compiler gem."
|
147
48
|
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
data/ext/ffruby/extconf.rb
CHANGED
@@ -1,13 +1,26 @@
|
|
1
|
-
#!/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "mkmf"
|
4
|
+
|
4
5
|
dir_config("ffmpeg")
|
6
|
+
|
7
|
+
%w( avformat avcodec ).each do |lib|
|
8
|
+
header = "#{lib}.h"
|
9
|
+
result = false
|
10
|
+
|
11
|
+
[ "lib#{lib}", "ffmpeg" ].each do |dir|
|
12
|
+
path = File.join(dir, header)
|
13
|
+
|
14
|
+
if checking_for(path) { try_cpp(cpp_include(path)) }
|
15
|
+
result = path
|
16
|
+
break
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
$defs.push "-D#{lib.upcase}_H_PATH=\"<#{result || header}>\""
|
21
|
+
end
|
22
|
+
|
5
23
|
have_library("avformat")
|
6
24
|
have_library("avcodec")
|
7
|
-
create_makefile("ffruby")
|
8
25
|
|
9
|
-
|
10
|
-
if `uname -a`.match(/i386/)
|
11
|
-
`sed '1,$s/-arch ppc//' Makefile >> ./Makefile.tmp`
|
12
|
-
`mv ./Makefile.tmp Makefile`
|
13
|
-
end
|
26
|
+
create_makefile("ffruby")
|
data/ext/ffruby/ffruby.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2007 James Le Cuirot
|
2
|
+
* Copyright (c) 2007-2010 James Le Cuirot
|
3
3
|
*
|
4
4
|
* This file is part of FFruby.
|
5
5
|
*
|
@@ -18,18 +18,53 @@
|
|
18
18
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
19
|
*/
|
20
20
|
|
21
|
-
#
|
22
|
-
#include <ruby.h>
|
23
|
-
#include <ffmpeg/avformat.h>
|
24
|
-
#include <ffmpeg/avcodec.h>
|
21
|
+
#include "ffruby.h"
|
25
22
|
|
26
23
|
extern void Init_ffrf();
|
27
24
|
extern void Init_ffrs();
|
28
25
|
|
26
|
+
/* Returns an array of the input and output formats supported by
|
27
|
+
* FFmpeg. This method will hopefully be expanded to return more than
|
28
|
+
* just names in the future. */
|
29
|
+
static VALUE ffruby_formats(VALUE self, VALUE klass)
|
30
|
+
{
|
31
|
+
AVInputFormat *ifmt;
|
32
|
+
AVOutputFormat *ofmt;
|
33
|
+
VALUE array = rb_ary_new();
|
34
|
+
|
35
|
+
for (ifmt = av_iformat_next(NULL); ifmt; ifmt = av_iformat_next(ifmt))
|
36
|
+
rb_ary_push(array, rb_str_new2(ifmt->name));
|
37
|
+
|
38
|
+
for (ofmt = av_oformat_next(NULL); ofmt; ofmt = av_oformat_next(ofmt))
|
39
|
+
rb_ary_push(array, rb_str_new2(ofmt->name));
|
40
|
+
|
41
|
+
return rb_funcall(rb_funcall(array, rb_intern("uniq"), 0), rb_intern("sort"), 0);
|
42
|
+
}
|
43
|
+
|
44
|
+
/* Returns an array of the codecs supported by FFmpeg. This method
|
45
|
+
* will hopefully be expanded to return more than just names in the
|
46
|
+
* future. */
|
47
|
+
static VALUE ffruby_codecs(VALUE self, VALUE klass)
|
48
|
+
{
|
49
|
+
AVCodec *codec;
|
50
|
+
VALUE array = rb_ary_new();
|
51
|
+
|
52
|
+
for (codec = av_codec_next(NULL); codec; codec = av_codec_next(codec))
|
53
|
+
rb_ary_push(array, rb_str_new2(codec->name));
|
54
|
+
|
55
|
+
return rb_funcall(rb_funcall(array, rb_intern("uniq"), 0), rb_intern("sort"), 0);
|
56
|
+
}
|
57
|
+
|
58
|
+
/* Top level module for the FFruby classes. Provides access to
|
59
|
+
* information about FFmpeg itself. */
|
29
60
|
void Init_ffruby()
|
30
61
|
{
|
31
62
|
av_register_all();
|
32
|
-
|
63
|
+
|
64
|
+
mFFruby = rb_define_module("FFruby");
|
65
|
+
rb_define_module_function(mFFruby, "formats", ffruby_formats, 0);
|
66
|
+
rb_define_module_function(mFFruby, "codecs", ffruby_codecs, 0);
|
67
|
+
|
33
68
|
Init_ffrf();
|
34
69
|
Init_ffrs();
|
35
70
|
}
|
data/ext/ffruby/ffruby.h
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2007-2010 James Le Cuirot
|
3
|
+
*
|
4
|
+
* This file is part of FFruby.
|
5
|
+
*
|
6
|
+
* FFruby is free software; you can redistribute it and/or
|
7
|
+
* modify it under the terms of the GNU Lesser General Public
|
8
|
+
* License as published by the Free Software Foundation; either
|
9
|
+
* version 2.1 of the License, or (at your option) any later version.
|
10
|
+
*
|
11
|
+
* FFruby is distributed in the hope that it will be useful,
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
* Lesser General Public License for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Lesser General Public
|
17
|
+
* License along with FFmpeg; if not, write to the Free Software
|
18
|
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
*/
|
20
|
+
|
21
|
+
#ifndef _FFRUBY_H_
|
22
|
+
#define _FFRUBY_H_
|
23
|
+
|
24
|
+
#include <ruby.h>
|
25
|
+
#include AVFORMAT_H_PATH
|
26
|
+
#include AVCODEC_H_PATH
|
27
|
+
|
28
|
+
VALUE mFFruby;
|
29
|
+
VALUE cFFrubyFile;
|
30
|
+
VALUE cFFrubyStream;
|
31
|
+
VALUE cFFrubyVideoStream;
|
32
|
+
VALUE cFFrubyAudioStream;
|
33
|
+
|
34
|
+
#endif
|
data/ext/ffruby/ffrubyfile.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2007 James Le Cuirot
|
2
|
+
* Copyright (c) 2007-2010 James Le Cuirot
|
3
3
|
*
|
4
4
|
* This file is part of FFruby.
|
5
5
|
*
|
@@ -18,21 +18,17 @@
|
|
18
18
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
19
|
*/
|
20
20
|
|
21
|
-
#
|
22
|
-
#include <
|
23
|
-
#include <ffmpeg/avformat.h>
|
24
|
-
#include <ffmpeg/avcodec.h>
|
21
|
+
#include "ffruby.h"
|
22
|
+
#include <string.h>
|
25
23
|
#include <stdio.h>
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
extern VALUE cFFrubyVideoStream;
|
30
|
-
extern VALUE cFFrubyAudioStream;
|
25
|
+
/* Satisfy stupid RDoc. This hopefully gets optimised away. */
|
26
|
+
static void rdoc() { mFFruby = rb_define_module("FFruby"); }
|
31
27
|
|
32
28
|
static void ffrf_free(AVFormatContext *fmt)
|
33
29
|
{
|
34
30
|
unsigned int i;
|
35
|
-
|
31
|
+
|
36
32
|
if (fmt != NULL)
|
37
33
|
{
|
38
34
|
for (i = 0; i < fmt->nb_streams; i++)
|
@@ -40,11 +36,16 @@ static void ffrf_free(AVFormatContext *fmt)
|
|
40
36
|
if (fmt->streams[i]->codec->codec != NULL)
|
41
37
|
avcodec_close(fmt->streams[i]->codec);
|
42
38
|
}
|
43
|
-
|
39
|
+
|
44
40
|
av_close_input_file(fmt);
|
45
41
|
}
|
46
42
|
}
|
47
43
|
|
44
|
+
static VALUE ffrf_alloc(VALUE klass)
|
45
|
+
{
|
46
|
+
return Data_Wrap_Struct(klass, 0, ffrf_free, NULL);
|
47
|
+
}
|
48
|
+
|
48
49
|
static AVFormatContext* ffrf_get_fmt(VALUE self)
|
49
50
|
{
|
50
51
|
AVFormatContext *fmt;
|
@@ -52,97 +53,104 @@ static AVFormatContext* ffrf_get_fmt(VALUE self)
|
|
52
53
|
return fmt;
|
53
54
|
}
|
54
55
|
|
55
|
-
|
56
|
-
{
|
57
|
-
return Data_Wrap_Struct(klass, 0, ffrf_free, NULL);
|
58
|
-
}
|
59
|
-
|
56
|
+
/* Returns the title string. */
|
60
57
|
static VALUE ffrf_title(VALUE self)
|
61
58
|
{
|
62
59
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
63
60
|
return rb_str_new2(fmt->title);
|
64
61
|
}
|
65
62
|
|
63
|
+
/* Returns the author string. */
|
66
64
|
static VALUE ffrf_author(VALUE self)
|
67
65
|
{
|
68
66
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
69
67
|
return rb_str_new2(fmt->author);
|
70
68
|
}
|
71
69
|
|
70
|
+
/* Returns the copyright string. */
|
72
71
|
static VALUE ffrf_copyright(VALUE self)
|
73
72
|
{
|
74
73
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
75
74
|
return rb_str_new2(fmt->copyright);
|
76
75
|
}
|
77
76
|
|
77
|
+
/* Returns the comment string. */
|
78
78
|
static VALUE ffrf_comment(VALUE self)
|
79
79
|
{
|
80
80
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
81
81
|
return rb_str_new2(fmt->comment);
|
82
82
|
}
|
83
83
|
|
84
|
+
/* Returns the album string. */
|
84
85
|
static VALUE ffrf_album(VALUE self)
|
85
86
|
{
|
86
87
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
87
88
|
return rb_str_new2(fmt->album);
|
88
89
|
}
|
89
90
|
|
91
|
+
/* Returns the genre string. */
|
90
92
|
static VALUE ffrf_genre(VALUE self)
|
91
93
|
{
|
92
94
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
93
95
|
return rb_str_new2(fmt->genre);
|
94
96
|
}
|
95
97
|
|
98
|
+
/* Returns the year. */
|
96
99
|
static VALUE ffrf_year(VALUE self)
|
97
100
|
{
|
98
101
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
99
102
|
return INT2NUM(fmt->year);
|
100
103
|
}
|
101
104
|
|
105
|
+
/* Returns the track number. */
|
102
106
|
static VALUE ffrf_track(VALUE self)
|
103
107
|
{
|
104
108
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
105
109
|
return INT2NUM(fmt->track);
|
106
110
|
}
|
107
111
|
|
112
|
+
/* Returns the duration in seconds as a float. */
|
108
113
|
static VALUE ffrf_duration(VALUE self)
|
109
114
|
{
|
110
115
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
111
116
|
return rb_float_new((double) fmt->duration / (double) AV_TIME_BASE);
|
112
117
|
}
|
113
118
|
|
119
|
+
/* Returns the bit rate. */
|
114
120
|
static VALUE ffrf_bit_rate(VALUE self)
|
115
121
|
{
|
116
122
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
117
123
|
return INT2NUM(fmt->bit_rate);
|
118
124
|
}
|
119
125
|
|
126
|
+
/* Returns the format name. */
|
120
127
|
static VALUE ffrf_format(VALUE self)
|
121
128
|
{
|
122
129
|
AVFormatContext *fmt = ffrf_get_fmt(self);
|
123
130
|
return rb_str_new2(fmt->iformat->name);
|
124
131
|
}
|
125
132
|
|
133
|
+
/* Returns an array of streams contained within this file. */
|
126
134
|
static VALUE ffrf_streams(VALUE self)
|
127
135
|
{
|
128
136
|
unsigned int i;
|
129
137
|
AVFormatContext *fmt;
|
130
138
|
VALUE streams;
|
131
139
|
VALUE* args;
|
132
|
-
|
140
|
+
|
133
141
|
if ((streams = rb_iv_get(self, "@streams")) == Qnil)
|
134
142
|
{
|
135
143
|
fmt = ffrf_get_fmt(self);
|
136
144
|
streams = rb_ary_new();
|
137
145
|
rb_iv_set(self, "@streams", streams);
|
138
|
-
|
146
|
+
|
139
147
|
args = (VALUE*) ALLOCA_N(VALUE*, 2);
|
140
148
|
args[0] = self;
|
141
|
-
|
149
|
+
|
142
150
|
for (i = 0; i < fmt->nb_streams; i++)
|
143
151
|
{
|
144
152
|
args[1] = INT2FIX(i);
|
145
|
-
|
153
|
+
|
146
154
|
switch (fmt->streams[i]->codec->codec_type)
|
147
155
|
{
|
148
156
|
case CODEC_TYPE_VIDEO:
|
@@ -156,7 +164,7 @@ static VALUE ffrf_streams(VALUE self)
|
|
156
164
|
}
|
157
165
|
}
|
158
166
|
}
|
159
|
-
|
167
|
+
|
160
168
|
return streams;
|
161
169
|
}
|
162
170
|
|
@@ -166,60 +174,77 @@ static VALUE ffrf_av_streams(VALUE self, VALUE klass)
|
|
166
174
|
VALUE streams;
|
167
175
|
VALUE typed_streams;
|
168
176
|
unsigned int i;
|
169
|
-
|
177
|
+
|
170
178
|
streams = rb_funcall(self, rb_intern("streams"), 0);
|
171
179
|
typed_streams = rb_ary_new();
|
172
180
|
Check_Type(streams, T_ARRAY);
|
173
|
-
|
181
|
+
|
174
182
|
for (i = 0; i < RARRAY(streams)->len; i++)
|
175
183
|
{
|
176
184
|
if (rb_obj_is_kind_of((stream = rb_ary_entry(streams, i)), klass))
|
177
185
|
rb_ary_push(typed_streams, stream);
|
178
186
|
}
|
179
|
-
|
187
|
+
|
180
188
|
return typed_streams;
|
181
189
|
}
|
182
190
|
|
191
|
+
/* Returns an array of video streams contained within this file. */
|
183
192
|
static VALUE ffrf_video_streams(VALUE self)
|
184
193
|
{
|
185
194
|
return ffrf_av_streams(self, cFFrubyVideoStream);
|
186
195
|
}
|
187
196
|
|
197
|
+
/* Returns an array of audio streams contained within this file. */
|
188
198
|
static VALUE ffrf_audio_streams(VALUE self)
|
189
199
|
{
|
190
200
|
return ffrf_av_streams(self, cFFrubyAudioStream);
|
191
201
|
}
|
192
202
|
|
203
|
+
/* call-seq:
|
204
|
+
* new(filename) -> FFruby::File
|
205
|
+
*
|
206
|
+
* Creates an FFruby::File instance using the given filename. */
|
193
207
|
static VALUE ffrf_initialize(VALUE self, VALUE filename)
|
194
208
|
{
|
209
|
+
size_t len;
|
195
210
|
char* msg;
|
196
211
|
AVFormatContext *fmt;
|
197
212
|
VALUE exception;
|
213
|
+
|
198
214
|
VALUE filename_str = rb_funcall(filename, rb_intern("to_s"), 0);
|
199
|
-
|
200
|
-
|
215
|
+
char* filename_ptr = RSTRING(filename_str)->ptr;
|
216
|
+
|
217
|
+
if (av_open_input_file(&fmt, filename_ptr, NULL, 0, NULL) != 0)
|
201
218
|
{
|
202
|
-
|
219
|
+
len = strlen("Cannot open file !") + strlen(filename_ptr) + 1;
|
220
|
+
msg = ALLOC_N(char, len);
|
221
|
+
snprintf(msg, len, "Cannot open file %s!", filename_ptr);
|
203
222
|
exception = rb_exc_new2(rb_eIOError, msg);
|
204
223
|
free(msg);
|
205
224
|
rb_exc_raise(exception);
|
206
225
|
}
|
207
|
-
|
226
|
+
|
208
227
|
if (av_find_stream_info(fmt) < 0)
|
209
228
|
{
|
210
|
-
|
229
|
+
len = strlen("Problem reading file !") + strlen(filename_ptr) + 1;
|
230
|
+
msg = ALLOC_N(char, len);
|
231
|
+
snprintf(msg, len, "Problem reading file %s!", filename_ptr);
|
211
232
|
exception = rb_exc_new2(rb_eIOError, msg);
|
212
233
|
free(msg);
|
213
234
|
rb_exc_raise(exception);
|
214
235
|
}
|
215
|
-
|
236
|
+
|
216
237
|
DATA_PTR(self) = fmt;
|
217
238
|
return self;
|
218
239
|
}
|
219
240
|
|
241
|
+
/* Document-class: FFruby::File
|
242
|
+
*
|
243
|
+
* An interface to FFmpeg on existing files. Provides access to
|
244
|
+
* metadata and stream instances. */
|
220
245
|
void Init_ffrf()
|
221
246
|
{
|
222
|
-
cFFrubyFile =
|
247
|
+
cFFrubyFile = rb_define_class_under(mFFruby, "File", rb_cObject);
|
223
248
|
rb_define_alloc_func(cFFrubyFile, ffrf_alloc);
|
224
249
|
rb_define_method(cFFrubyFile, "initialize", ffrf_initialize, 1);
|
225
250
|
rb_define_method(cFFrubyFile, "title", ffrf_title, 0);
|