ffmpeg-ruby 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.
- data/Manifest +16 -0
- data/README.rdoc +51 -0
- data/Rakefile +15 -0
- data/ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist +20 -0
- data/ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest +0 -0
- data/ext/ffmpeg_ruby/extconf.rb +26 -0
- data/ext/ffmpeg_ruby/ffmpeg_avcodec.c +199 -0
- data/ext/ffmpeg_ruby/ffmpeg_avcodec.h +27 -0
- data/ext/ffmpeg_ruby/ffmpeg_avformat.c +149 -0
- data/ext/ffmpeg_ruby/ffmpeg_avformat.h +28 -0
- data/ext/ffmpeg_ruby/ffmpeg_ruby.c +16 -0
- data/ext/ffmpeg_ruby/ffmpeg_ruby.h +3 -0
- data/ffmpeg-ruby.gemspec +31 -0
- data/lib/ffmpeg-ruby.rb +4 -0
- data/tasks/mac_specific.rake +9 -0
- data/test/test.rb +39 -0
- metadata +87 -0
data/Manifest
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Manifest
|
|
2
|
+
README.rdoc
|
|
3
|
+
Rakefile
|
|
4
|
+
ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist
|
|
5
|
+
ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest
|
|
6
|
+
ext/ffmpeg_ruby/extconf.rb
|
|
7
|
+
ext/ffmpeg_ruby/ffmpeg_avcodec.c
|
|
8
|
+
ext/ffmpeg_ruby/ffmpeg_avcodec.h
|
|
9
|
+
ext/ffmpeg_ruby/ffmpeg_avformat.c
|
|
10
|
+
ext/ffmpeg_ruby/ffmpeg_avformat.h
|
|
11
|
+
ext/ffmpeg_ruby/ffmpeg_ruby.c
|
|
12
|
+
ext/ffmpeg_ruby/ffmpeg_ruby.h
|
|
13
|
+
ffmpeg-ruby.gemspec
|
|
14
|
+
lib/ffmpeg-ruby.rb
|
|
15
|
+
tasks/mac_specific.rake
|
|
16
|
+
test/test.rb
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
= Ruby FFMpeg Library
|
|
2
|
+
|
|
3
|
+
"ffmpeg-ruby" is a ruby gem library (work in progress) that provides bindings allowing you to access the ffmpeg under ruby. FFMpeg is a cross-platform solution to record, convert and stream audio and video. It includes libavcodec - the leading audio/video codec library.
|
|
4
|
+
|
|
5
|
+
This implementation is starting by doing the translation for some of the functions in libavcodec and libavformat to ruby.
|
|
6
|
+
|
|
7
|
+
FFMpeg is provided by http://ffmpeg.org/ under the LGPL license.
|
|
8
|
+
|
|
9
|
+
This bindings gem is graciously provided by http://www.channels.com under the LGPL license.
|
|
10
|
+
|
|
11
|
+
== Installing
|
|
12
|
+
|
|
13
|
+
$ gem install ffmpeg-ruby
|
|
14
|
+
|
|
15
|
+
== Installation troubleshooting
|
|
16
|
+
|
|
17
|
+
If you run into trouble, it could be the C bundle not building. This is known to happen on MacOS 64-bit or with the ffmpeg from macports. You basically need to run ruby extconf yourself then.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
$ ruby extconf.rb
|
|
21
|
+
|
|
22
|
+
You may need to add +--with+ on mac, to point it to macports' /opt/local for the libraries.
|
|
23
|
+
|
|
24
|
+
This has worked on my snow leopard machine:
|
|
25
|
+
|
|
26
|
+
$ sudo port install ffmpeg
|
|
27
|
+
(go have coffee)
|
|
28
|
+
$ env ARCHFLAGS="-arch x86_64" ruby extconf.rb --with-avformat-dir=/opt/local
|
|
29
|
+
make
|
|
30
|
+
|
|
31
|
+
This will provide you with a bundle you can require.
|
|
32
|
+
|
|
33
|
+
== Usage
|
|
34
|
+
|
|
35
|
+
See the code on +test/+ for usage. But basically it goes like this:
|
|
36
|
+
|
|
37
|
+
require 'ffmpeg-ruby'
|
|
38
|
+
|
|
39
|
+
# Get a list of the video codecs supported
|
|
40
|
+
FFMpeg::AVCodec.supported_video_codecs
|
|
41
|
+
|
|
42
|
+
# Get a list of the audio codecs supported
|
|
43
|
+
FFMpeg::AVCodec.supported_video_codecs
|
|
44
|
+
|
|
45
|
+
# Create new AVFormatContext
|
|
46
|
+
f = FFMpeg::AVFormatContext.new("/path/to/my/video.mov")
|
|
47
|
+
|
|
48
|
+
f.codec_contexts.each{ |ctx|
|
|
49
|
+
puts ctx.name # The name of the codec this file uses.
|
|
50
|
+
}
|
|
51
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'echoe'
|
|
4
|
+
|
|
5
|
+
Echoe.new("ffmpeg-ruby", "0.1.0") do |p|
|
|
6
|
+
p.description = "FFMpeg Ruby Bridge. Call FFMpeg/LibAVCodec/LibAVFormat directly"
|
|
7
|
+
p.url = "http://github.com/hackerdude/ffmpeg-ruby"
|
|
8
|
+
p.author = "David Martinez"
|
|
9
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
|
10
|
+
p.development_dependencies = [] # TODO How to do native dependencies?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each{|ext| load ext }
|
|
15
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>English</string>
|
|
7
|
+
<key>CFBundleIdentifier</key>
|
|
8
|
+
<string>com.apple.xcode.dsym.conftest</string>
|
|
9
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
10
|
+
<string>6.0</string>
|
|
11
|
+
<key>CFBundlePackageType</key>
|
|
12
|
+
<string>dSYM</string>
|
|
13
|
+
<key>CFBundleSignature</key>
|
|
14
|
+
<string>????</string>
|
|
15
|
+
<key>CFBundleShortVersionString</key>
|
|
16
|
+
<string>1.0</string>
|
|
17
|
+
<key>CFBundleVersion</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
</plist>
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
#require 'rubygems'
|
|
3
|
+
#require 'ruby-debug'
|
|
4
|
+
#Debugger.start
|
|
5
|
+
|
|
6
|
+
def boom(v)
|
|
7
|
+
puts(v)
|
|
8
|
+
exit 1
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
#debugger
|
|
12
|
+
if RUBY_PLATFORM == "universal-darwin10.0"
|
|
13
|
+
# TODO Set the archflags to -arch x86_64 ONLY if it's a 64-bit snow leopard machine.
|
|
14
|
+
#ENV['ARCHFLAGS'] = "-arch i386 -arch x86_64"
|
|
15
|
+
$CFLAGS.sub!("-arch x86_64", "")
|
|
16
|
+
end
|
|
17
|
+
unless ( have_header("libavformat/avformat.h") ||
|
|
18
|
+
find_header("libavformat/avformat.h", "/opt/local/include", "/usr/local/include", "/usr/include") ) and
|
|
19
|
+
( have_library("avformat", "av_register_all") or
|
|
20
|
+
find_library("avformat", "av_register_all", "/opt/local/lib", "/usr/local/lib", "/usr/lib") )
|
|
21
|
+
boom(<<EOL)
|
|
22
|
+
You need to install or tell me where to find ffmpeg. Check the mkmf.log file to see what erred out.
|
|
23
|
+
EOL
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
create_makefile("ffmpeg_ruby")
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
#include <libavcodec/avcodec.h>
|
|
3
|
+
|
|
4
|
+
VALUE cFFMpegAVCodec;
|
|
5
|
+
VALUE cFFMpegAVCodecContext;
|
|
6
|
+
|
|
7
|
+
void AVCodec_mark(void *v) {}
|
|
8
|
+
void AVCodec_free(void *v) {}
|
|
9
|
+
|
|
10
|
+
void AVCodecContext_mark(AVCodecContext v) {}
|
|
11
|
+
void AVCodecContext_free(AVCodecContext v) {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
VALUE AVCodecContext_codec_type(VALUE self)
|
|
15
|
+
{
|
|
16
|
+
AVCodecContext *ptr;
|
|
17
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
18
|
+
VALUE result = INT2NUM(ptr->codec_type);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
VALUE codec_type_map()
|
|
23
|
+
{
|
|
24
|
+
VALUE result = rb_hash_new();
|
|
25
|
+
rb_hash_aset(result, INT2NUM(CODEC_TYPE_VIDEO), rb_str_new2("Video"));
|
|
26
|
+
rb_hash_aset(result, INT2NUM(CODEC_TYPE_AUDIO), rb_str_new2("Audio"));
|
|
27
|
+
rb_hash_aset(result, INT2NUM(CODEC_TYPE_DATA), rb_str_new2("Data"));
|
|
28
|
+
rb_hash_aset(result, INT2NUM(CODEC_TYPE_SUBTITLE), rb_str_new2("Subtitle"));
|
|
29
|
+
rb_hash_aset(result, INT2NUM(CODEC_TYPE_ATTACHMENT), rb_str_new2("Attachment"));
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
VALUE AVCodecContext_codec_id(VALUE self)
|
|
35
|
+
{
|
|
36
|
+
AVCodecContext *ptr;
|
|
37
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
38
|
+
VALUE result = INT2NUM(ptr->codec_id);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
VALUE AVCodecContext_width(VALUE self)
|
|
43
|
+
{
|
|
44
|
+
AVCodecContext *ptr;
|
|
45
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
46
|
+
VALUE result = INT2NUM(ptr->width);
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
VALUE AVCodecContext_height(VALUE self)
|
|
51
|
+
{
|
|
52
|
+
AVCodecContext *ptr;
|
|
53
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
54
|
+
VALUE result = INT2NUM(ptr->height);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
VALUE AVCodecContext_channels(VALUE self)
|
|
59
|
+
{
|
|
60
|
+
AVCodecContext *ptr;
|
|
61
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
62
|
+
VALUE result = INT2NUM(ptr->channels);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
VALUE AVCodecContext_sample_rate(VALUE self)
|
|
67
|
+
{
|
|
68
|
+
AVCodecContext *ptr;
|
|
69
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
70
|
+
VALUE result = INT2NUM(ptr->sample_rate);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
VALUE AVCodec_long_name(VALUE self)
|
|
75
|
+
{
|
|
76
|
+
char* tm;
|
|
77
|
+
AVCodec *ptr;
|
|
78
|
+
Data_Get_Struct(self, AVCodec, ptr);
|
|
79
|
+
tm = ptr->long_name;
|
|
80
|
+
return rb_str_new2(tm);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
VALUE AVCodec_name(VALUE self)
|
|
84
|
+
{
|
|
85
|
+
char* tm;
|
|
86
|
+
AVCodec *ptr;
|
|
87
|
+
Data_Get_Struct(self, AVCodec, ptr);
|
|
88
|
+
tm = ptr->name;
|
|
89
|
+
return rb_str_new2(tm);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
VALUE AVCodec_codec_type(VALUE self)
|
|
93
|
+
{
|
|
94
|
+
char* tm;
|
|
95
|
+
AVCodec *ptr;
|
|
96
|
+
Data_Get_Struct(self, AVCodec, ptr);
|
|
97
|
+
return INT2NUM(ptr->type);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
VALUE AVCodecContext_codec_long_name(VALUE self)
|
|
101
|
+
{
|
|
102
|
+
char* tm;
|
|
103
|
+
AVCodecContext *ptr;
|
|
104
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
105
|
+
if (ptr->codec == NULL)
|
|
106
|
+
return Qnil;
|
|
107
|
+
tm = ptr->codec->long_name;
|
|
108
|
+
return rb_str_new2(tm);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
VALUE AVCodecContext_codec_name(VALUE self)
|
|
112
|
+
{
|
|
113
|
+
char* tm;
|
|
114
|
+
AVCodecContext *ptr;
|
|
115
|
+
Data_Get_Struct(self, AVCodecContext, ptr);
|
|
116
|
+
if (ptr->codec == NULL)
|
|
117
|
+
return Qnil;
|
|
118
|
+
tm = ptr->codec->name;
|
|
119
|
+
return rb_str_new2(tm);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
VALUE supported_avcodecs()
|
|
123
|
+
{
|
|
124
|
+
VALUE result = rb_hash_new();
|
|
125
|
+
AVCodec *pNextCodec = NULL;
|
|
126
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
127
|
+
while (pNextCodec != NULL) {
|
|
128
|
+
VALUE sNextCodecName = rb_str_new2(pNextCodec->name);
|
|
129
|
+
//VALUE sNextCodecLongName = rb_str_new2(pNextCodec->long_name);
|
|
130
|
+
VALUE codec = Data_Wrap_Struct(cFFMpegAVCodec, AVCodecContext_mark, AVCodecContext_free, pNextCodec);
|
|
131
|
+
rb_hash_aset(result, sNextCodecName, codec);
|
|
132
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
VALUE supported_video_codecs()
|
|
138
|
+
{
|
|
139
|
+
VALUE result = rb_hash_new();
|
|
140
|
+
AVCodec *pNextCodec = NULL;
|
|
141
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
142
|
+
while (pNextCodec != NULL) {
|
|
143
|
+
if (pNextCodec->type==CODEC_TYPE_VIDEO) {
|
|
144
|
+
VALUE sNextCodecName = rb_str_new2(pNextCodec->name);
|
|
145
|
+
//VALUE sNextCodecLongName = rb_str_new2(pNextCodec->long_name);
|
|
146
|
+
VALUE codec = Data_Wrap_Struct(cFFMpegAVCodec, AVCodecContext_mark, AVCodecContext_free, pNextCodec);
|
|
147
|
+
rb_hash_aset(result, sNextCodecName, codec);
|
|
148
|
+
}
|
|
149
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
VALUE supported_audio_codecs()
|
|
155
|
+
{
|
|
156
|
+
VALUE result = rb_hash_new();
|
|
157
|
+
AVCodec *pNextCodec = NULL;
|
|
158
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
159
|
+
while (pNextCodec != NULL) {
|
|
160
|
+
if (pNextCodec->type==CODEC_TYPE_AUDIO) {
|
|
161
|
+
VALUE sNextCodecName = rb_str_new2(pNextCodec->name);
|
|
162
|
+
//VALUE sNextCodecLongName = rb_str_new2(pNextCodec->long_name);
|
|
163
|
+
VALUE codec = Data_Wrap_Struct(cFFMpegAVCodec, AVCodecContext_mark, AVCodecContext_free, pNextCodec);
|
|
164
|
+
rb_hash_aset(result, sNextCodecName, codec);
|
|
165
|
+
}
|
|
166
|
+
pNextCodec = av_codec_next(pNextCodec);
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
void Init_ffmpeg_ruby_avcodec(VALUE module)
|
|
172
|
+
{
|
|
173
|
+
|
|
174
|
+
cFFMpegAVCodec = rb_define_class_under(module, "AVCodec", rb_cObject);
|
|
175
|
+
rb_define_method(cFFMpegAVCodec, "name", AVCodec_name, 0);
|
|
176
|
+
rb_define_method(cFFMpegAVCodec, "long_name", AVCodec_long_name, 0);
|
|
177
|
+
rb_define_method(cFFMpegAVCodec, "codec_type", AVCodec_codec_type, 0);
|
|
178
|
+
rb_define_singleton_method(cFFMpegAVCodec, "supported_avcodecs", supported_avcodecs, 0);
|
|
179
|
+
rb_define_singleton_method(cFFMpegAVCodec, "supported_video_codecs", supported_video_codecs, 0);
|
|
180
|
+
rb_define_singleton_method(cFFMpegAVCodec, "supported_audio_codecs", supported_audio_codecs, 0);
|
|
181
|
+
cFFMpegAVCodecContext = rb_define_class_under(module, "AVCodecContext", rb_cObject);
|
|
182
|
+
rb_define_method(cFFMpegAVCodecContext, "long_name", AVCodecContext_codec_long_name, 0);
|
|
183
|
+
rb_define_method(cFFMpegAVCodecContext, "name", AVCodecContext_codec_name, 0);
|
|
184
|
+
rb_define_method(cFFMpegAVCodecContext, "codec_type", AVCodecContext_codec_type, 0);
|
|
185
|
+
rb_define_method(cFFMpegAVCodecContext, "codec_id", AVCodecContext_codec_id, 0);
|
|
186
|
+
rb_define_method(cFFMpegAVCodecContext, "width", AVCodecContext_width, 0);
|
|
187
|
+
rb_define_method(cFFMpegAVCodecContext, "height", AVCodecContext_height, 0);
|
|
188
|
+
rb_define_method(cFFMpegAVCodecContext, "channels", AVCodecContext_channels, 0);
|
|
189
|
+
rb_define_method(cFFMpegAVCodecContext, "sample_rate", AVCodecContext_sample_rate, 0);
|
|
190
|
+
|
|
191
|
+
// Codec Types, for AVCodecContext
|
|
192
|
+
rb_define_const(module, "CODEC_TYPE_VIDEO", INT2NUM(CODEC_TYPE_VIDEO));
|
|
193
|
+
rb_define_const(module, "CODEC_TYPE_AUDIO", INT2NUM(CODEC_TYPE_AUDIO));
|
|
194
|
+
rb_define_const(module, "CODEC_TYPE_DATA", INT2NUM(CODEC_TYPE_DATA));
|
|
195
|
+
rb_define_const(module, "CODEC_TYPE_SUBTITLE", INT2NUM(CODEC_TYPE_SUBTITLE));
|
|
196
|
+
rb_define_const(module, "CODEC_TYPE_ATTACHMENT", INT2NUM(CODEC_TYPE_ATTACHMENT));
|
|
197
|
+
rb_define_const(module, "MAP_CODEC_TYPES", codec_type_map());
|
|
198
|
+
|
|
199
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
VALUE cFFMpegAVCodecContext;
|
|
2
|
+
|
|
3
|
+
void Init_ffmpeg_ruby_avcodec(VALUE module)
|
|
4
|
+
|
|
5
|
+
void AVCodec_mark(void *v);
|
|
6
|
+
void AVCodec_free(void *v);
|
|
7
|
+
|
|
8
|
+
void AVCodecContext_mark(AVCodecContext v);
|
|
9
|
+
void AVCodecContext_free(AVCodecContext v);
|
|
10
|
+
|
|
11
|
+
VALUE AVCodecContext_codec_type(VALUE self);
|
|
12
|
+
VALUE codec_type_map();
|
|
13
|
+
|
|
14
|
+
VALUE AVCodecContext_codec_id(VALUE self);
|
|
15
|
+
VALUE AVCodecContext_width(VALUE self);
|
|
16
|
+
VALUE AVCodecContext_height(VALUE self);
|
|
17
|
+
VALUE AVCodecContext_channels(VALUE self);
|
|
18
|
+
VALUE AVCodecContext_sample_rate(VALUE self);
|
|
19
|
+
VALUE AVCodec_long_name(VALUE self);
|
|
20
|
+
VALUE AVCodec_name(VALUE self);
|
|
21
|
+
VALUE AVCodec_codec_type(VALUE self);
|
|
22
|
+
VALUE AVCodecContext_codec_long_name(VALUE self);
|
|
23
|
+
VALUE AVCodecContext_codec_name(VALUE self);
|
|
24
|
+
VALUE supported_avcodecs();
|
|
25
|
+
VALUE supported_video_codecs();
|
|
26
|
+
VALUE supported_audio_codecs();
|
|
27
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
#include <libavformat/avformat.h>
|
|
3
|
+
#include "ffmpeg_avformat.h"
|
|
4
|
+
|
|
5
|
+
void AVFormatContext_mark(void *v) {}
|
|
6
|
+
|
|
7
|
+
void AVFormatContext_free(void *v) {
|
|
8
|
+
// TODO Figure out how to avoid double-closing.
|
|
9
|
+
//AVFormatContext* f = (AVFormatContext*)v;
|
|
10
|
+
//if (f->filename != NULL)
|
|
11
|
+
//av_close_input_file(v);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
void AVOutputFormat_mark(void *v){}
|
|
15
|
+
void AVOutputFormat_free(void *v){}
|
|
16
|
+
|
|
17
|
+
VALUE supported_avformats()
|
|
18
|
+
{
|
|
19
|
+
VALUE result = rb_hash_new();
|
|
20
|
+
AVOutputFormat *pNext = NULL;
|
|
21
|
+
pNext = av_oformat_next(pNext);
|
|
22
|
+
while (pNext != NULL) {
|
|
23
|
+
VALUE sNextFormatName = rb_str_new2(pNext->name);
|
|
24
|
+
//VALUE sNextLongName = rb_str_new2(pNext->long_name);
|
|
25
|
+
VALUE format = Data_Wrap_Struct(cFFMpegAVOutputFormat, AVOutputFormat_mark, AVOutputFormat_free, pNext);
|
|
26
|
+
rb_obj_call_init(result, 0, 0);
|
|
27
|
+
rb_hash_aset(result, sNextFormatName, format);
|
|
28
|
+
pNext = av_codec_next(pNext);
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
VALUE AVFormatContext_dump_format(VALUE self) {
|
|
35
|
+
AVFormatContext *ptr;
|
|
36
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
37
|
+
dump_format(ptr, 0, ptr->filename, 0);
|
|
38
|
+
return Qnil;
|
|
39
|
+
}
|
|
40
|
+
VALUE AVFormatContext_duration(VALUE self) {
|
|
41
|
+
AVFormatContext *ptr;
|
|
42
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
43
|
+
//ptr->filename = NULL;
|
|
44
|
+
return INT2NUM(ptr->duration);
|
|
45
|
+
}
|
|
46
|
+
VALUE AVFormatContext_close_file(VALUE self) {
|
|
47
|
+
AVFormatContext *ptr;
|
|
48
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
49
|
+
av_close_input_file(ptr);
|
|
50
|
+
//ptr->filename = NULL;
|
|
51
|
+
return Qnil;
|
|
52
|
+
}
|
|
53
|
+
VALUE AVFormatContext_new(VALUE klaas, VALUE ruby_filename) {
|
|
54
|
+
Check_Type(ruby_filename, T_STRING);
|
|
55
|
+
char* filename = StringValuePtr(ruby_filename);
|
|
56
|
+
|
|
57
|
+
AVFormatContext *pFormatCtx;
|
|
58
|
+
// Open video file
|
|
59
|
+
if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) {
|
|
60
|
+
rb_raise(rb_eRuntimeError, "Could not open video file %s", filename);
|
|
61
|
+
return NULL;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Retrieve stream information
|
|
65
|
+
if(av_find_stream_info(pFormatCtx)<0) {
|
|
66
|
+
rb_raise(rb_eRuntimeError, "Could find the stream information in file %s", filename);
|
|
67
|
+
return NULL; // Couldn't find stream information
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
VALUE result = Data_Wrap_Struct(klaas, AVFormatContext_mark, AVFormatContext_free, pFormatCtx);
|
|
71
|
+
rb_obj_call_init(result, 0, 0);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Return all the AVCodecContext entries for all streams in the file */
|
|
76
|
+
VALUE AVFormatContext_codec_contexts(VALUE self) {
|
|
77
|
+
AVFormatContext *ptr;
|
|
78
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
79
|
+
VALUE result = rb_ary_new();
|
|
80
|
+
int i, videoStream;
|
|
81
|
+
videoStream=-1;
|
|
82
|
+
for(i=0; i<ptr->nb_streams; i++) {
|
|
83
|
+
// Get a pointer to the codec context for the video stream
|
|
84
|
+
AVCodecContext *pCodecCtx = ptr->streams[i]->codec;
|
|
85
|
+
AVCodec *pCodec;
|
|
86
|
+
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
|
|
87
|
+
pCodecCtx->codec = pCodec;
|
|
88
|
+
|
|
89
|
+
// Turn it into something ruby can understand
|
|
90
|
+
VALUE rCodec = Data_Wrap_Struct(cFFMpegAVCodecContext, AVCodecContext_mark, AVCodecContext_free, pCodecCtx);
|
|
91
|
+
rb_obj_call_init(rCodec,0,0);
|
|
92
|
+
rb_ary_push(result, rCodec);
|
|
93
|
+
}
|
|
94
|
+
//if(videoStream==-1) {
|
|
95
|
+
//rb_raise(rb_eRuntimeError, "No video streams here!");
|
|
96
|
+
//return Qnil;
|
|
97
|
+
//}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
VALUE AVFormatContext_title(VALUE self) {
|
|
102
|
+
AVFormatContext *ptr;
|
|
103
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
104
|
+
return rb_str_new2(ptr->title);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
VALUE AVFormatContext_author(VALUE self) {
|
|
108
|
+
AVFormatContext *ptr;
|
|
109
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
110
|
+
return rb_str_new2(ptr->author);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
VALUE AVFormatContext_copyright(VALUE self) {
|
|
114
|
+
AVFormatContext *ptr;
|
|
115
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
116
|
+
return rb_str_new2(ptr->copyright);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
VALUE AVFormatContext_bit_rate(VALUE self) {
|
|
120
|
+
AVFormatContext *ptr;
|
|
121
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
122
|
+
return INT2NUM(ptr->bit_rate);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
VALUE AVFormatContext_album(VALUE self) {
|
|
126
|
+
AVFormatContext *ptr;
|
|
127
|
+
Data_Get_Struct(self, AVFormatContext, ptr);
|
|
128
|
+
return rb_str_new2(ptr->album);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
void Init_ffmpeg_ruby_avformat(VALUE module)
|
|
133
|
+
{
|
|
134
|
+
|
|
135
|
+
cFFMpegAVFormatContext = rb_define_class_under(module, "AVFormatContext", rb_cObject);
|
|
136
|
+
rb_define_singleton_method(cFFMpegAVFormatContext, "new", AVFormatContext_new, 1);
|
|
137
|
+
rb_define_method(cFFMpegAVFormatContext, "close_file", AVFormatContext_close_file, 0);
|
|
138
|
+
rb_define_method(cFFMpegAVFormatContext, "duration", AVFormatContext_duration, 0);
|
|
139
|
+
rb_define_method(cFFMpegAVFormatContext, "title", AVFormatContext_title, 0);
|
|
140
|
+
rb_define_method(cFFMpegAVFormatContext, "copyright", AVFormatContext_copyright, 0);
|
|
141
|
+
rb_define_method(cFFMpegAVFormatContext, "author", AVFormatContext_author, 0);
|
|
142
|
+
rb_define_method(cFFMpegAVFormatContext, "album", AVFormatContext_album, 0);
|
|
143
|
+
rb_define_method(cFFMpegAVFormatContext, "bit_rate", AVFormatContext_bit_rate, 0);
|
|
144
|
+
rb_define_method(cFFMpegAVFormatContext, "codec_contexts", AVFormatContext_codec_contexts, 0);
|
|
145
|
+
rb_define_method(cFFMpegAVFormatContext, "dump_format", AVFormatContext_dump_format, 0);
|
|
146
|
+
|
|
147
|
+
cFFMpegAVOutputFormat = rb_define_class_under(module, "AVOutputFormat", rb_cObject);
|
|
148
|
+
rb_define_singleton_method(cFFMpegAVOutputFormat, "supported_avformats", supported_avformats, 0);
|
|
149
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#include <libavformat/avformat.h>
|
|
2
|
+
#include <ruby.h>
|
|
3
|
+
|
|
4
|
+
VALUE cFFMpegAVFormatContext;
|
|
5
|
+
VALUE cFFMpegAVOutputFormat;
|
|
6
|
+
|
|
7
|
+
void AVOutputFormat_mark(void *v);
|
|
8
|
+
void AVOutputFormat_free(void *v);
|
|
9
|
+
|
|
10
|
+
void AVFormatContext_mark(void *v);
|
|
11
|
+
void AVFormatContext_free(void *v);
|
|
12
|
+
|
|
13
|
+
VALUE AVFormatContext_dump_format(VALUE);
|
|
14
|
+
VALUE AVFormatContext_duration(VALUE);
|
|
15
|
+
VALUE AVFormatContext_close_file(VALUE);
|
|
16
|
+
VALUE AVFormatContext_new(VALUE, VALUE);
|
|
17
|
+
VALUE AVFormatContext_codec_contexts(VALUE);
|
|
18
|
+
VALUE AVFormatContext_title(VALUE);
|
|
19
|
+
VALUE AVFormatContext_author(VALUE);
|
|
20
|
+
VALUE AVFormatContext_copyright(VALUE);
|
|
21
|
+
VALUE AVFormatContext_bit_rate(VALUE);
|
|
22
|
+
VALUE AVFormatContext_album(VALUE);
|
|
23
|
+
void Init_ffmpeg_ruby_avformat(VALUE module);
|
|
24
|
+
|
|
25
|
+
// Forward declaring some necessary avcodec stuff
|
|
26
|
+
void AVCodecContext_mark(void *v);
|
|
27
|
+
void AVCodecContext_free(void *v);
|
|
28
|
+
extern VALUE cFFMpegAVCodecContext;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#include "ffmpeg_ruby.h"
|
|
2
|
+
|
|
3
|
+
#include <libavcodec/avcodec.h>
|
|
4
|
+
#include <libavformat/avformat.h>
|
|
5
|
+
|
|
6
|
+
/** FFMpeg Module */
|
|
7
|
+
VALUE mFFMpeg;
|
|
8
|
+
/** *** Ruby Interface *** **/
|
|
9
|
+
void Init_ffmpeg_ruby()
|
|
10
|
+
{
|
|
11
|
+
av_register_all();
|
|
12
|
+
mFFMpeg = rb_define_module("FFMpeg");
|
|
13
|
+
Init_ffmpeg_ruby_avcodec(mFFMpeg);
|
|
14
|
+
Init_ffmpeg_ruby_avformat(mFFMpeg);
|
|
15
|
+
}
|
|
16
|
+
|
data/ffmpeg-ruby.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{ffmpeg-ruby}
|
|
5
|
+
s.version = "0.1.0"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["David Martinez"]
|
|
9
|
+
s.date = %q{2010-02-10}
|
|
10
|
+
s.description = %q{FFMpeg Ruby Bridge. Call FFMpeg/LibAVCodec/LibAVFormat directly}
|
|
11
|
+
s.email = %q{}
|
|
12
|
+
s.extensions = ["ext/ffmpeg_ruby/extconf.rb"]
|
|
13
|
+
s.extra_rdoc_files = ["README.rdoc", "ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist", "ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest", "ext/ffmpeg_ruby/extconf.rb", "ext/ffmpeg_ruby/ffmpeg_avcodec.c", "ext/ffmpeg_ruby/ffmpeg_avcodec.h", "ext/ffmpeg_ruby/ffmpeg_avformat.c", "ext/ffmpeg_ruby/ffmpeg_avformat.h", "ext/ffmpeg_ruby/ffmpeg_ruby.c", "ext/ffmpeg_ruby/ffmpeg_ruby.h", "lib/ffmpeg-ruby.rb", "tasks/mac_specific.rake"]
|
|
14
|
+
s.files = ["Manifest", "README.rdoc", "Rakefile", "ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist", "ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest", "ext/ffmpeg_ruby/extconf.rb", "ext/ffmpeg_ruby/ffmpeg_avcodec.c", "ext/ffmpeg_ruby/ffmpeg_avcodec.h", "ext/ffmpeg_ruby/ffmpeg_avformat.c", "ext/ffmpeg_ruby/ffmpeg_avformat.h", "ext/ffmpeg_ruby/ffmpeg_ruby.c", "ext/ffmpeg_ruby/ffmpeg_ruby.h", "ffmpeg-ruby.gemspec", "lib/ffmpeg-ruby.rb", "tasks/mac_specific.rake", "test/test.rb"]
|
|
15
|
+
s.homepage = %q{http://github.com/hackerdude/ffmpeg-ruby}
|
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ffmpeg-ruby", "--main", "README.rdoc"]
|
|
17
|
+
s.require_paths = ["lib", "ext"]
|
|
18
|
+
s.rubyforge_project = %q{ffmpeg-ruby}
|
|
19
|
+
s.rubygems_version = %q{1.3.5}
|
|
20
|
+
s.summary = %q{FFMpeg Ruby Bridge. Call FFMpeg/LibAVCodec/LibAVFormat directly}
|
|
21
|
+
|
|
22
|
+
if s.respond_to? :specification_version then
|
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
24
|
+
s.specification_version = 3
|
|
25
|
+
|
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
27
|
+
else
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/ffmpeg-ruby.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
task :compile_mac do
|
|
2
|
+
puts "Compiling on a mac"
|
|
3
|
+
`cd ext/ffmpeg_ruby && env ARCHFLAGS="-arch x86_64" ruby extconf.rb --with-avformat-dir=/opt/local && make`
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
task :clean_mac => :clean do
|
|
7
|
+
puts "Cleaning on a mac"
|
|
8
|
+
`rm -rf ext/ffmpeg_ruby/conftest.dSYM`
|
|
9
|
+
end
|
data/test/test.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/ffmpeg-ruby"
|
|
2
|
+
|
|
3
|
+
puts "Here are the video codecs I support, of the #{FFMpeg::AVCodec.supported_avcodecs.length} codecs:"
|
|
4
|
+
FFMpeg::AVCodec.supported_video_codecs.each{|k,v|
|
|
5
|
+
puts " - #{k}=#{v.long_name} (#{v.name}) of type #{FFMpeg::MAP_CODEC_TYPES[v.codec_type]}"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
FFMpeg::AVCodec.supported_audio_codecs.each{|k,v|
|
|
9
|
+
puts " - #{k}=#{v.long_name} (#{v.name}) of type #{FFMpeg::MAP_CODEC_TYPES[v.codec_type]}"
|
|
10
|
+
}
|
|
11
|
+
puts "Creating new AVFormatContext"
|
|
12
|
+
filename = '/Users/david/channels-reader/public/videos/Channels_Playlist_WEB.mov'
|
|
13
|
+
if ARGV.length > 0
|
|
14
|
+
filename = ARGV[0]
|
|
15
|
+
end
|
|
16
|
+
f = FFMpeg::AVFormatContext.new(filename)
|
|
17
|
+
"Format Information:"
|
|
18
|
+
puts " Duration: #{f.duration}"
|
|
19
|
+
puts " Title: #{f.title}"
|
|
20
|
+
puts " Copyright: #{f.copyright}"
|
|
21
|
+
puts " Author: #{f.author}"
|
|
22
|
+
puts " Album: #{f.album}"
|
|
23
|
+
puts " Bit Rate: #{f.bit_rate}"
|
|
24
|
+
|
|
25
|
+
puts "\nCodec Information for #{filename}"
|
|
26
|
+
f.codec_contexts.each_with_index{|ctx,i|
|
|
27
|
+
puts "Codec info for stream ##{i}"
|
|
28
|
+
puts " Type: #{ctx.codec_type} (#{FFMpeg::MAP_CODEC_TYPES[ctx.codec_type]})"
|
|
29
|
+
puts " Name: #{ctx.name}"
|
|
30
|
+
puts " Long Name: #{ctx.long_name}"
|
|
31
|
+
puts " Width: #{ctx.width}"
|
|
32
|
+
puts " Height: #{ctx.height}"
|
|
33
|
+
puts " Audio Channels: #{ctx.channels}"
|
|
34
|
+
puts " Audio Sample Rate: #{ctx.sample_rate}"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
puts "-- Now dumping the format:"
|
|
38
|
+
f.dump_format
|
|
39
|
+
|
metadata
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ffmpeg-ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- David Martinez
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2010-02-10 00:00:00 -08:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: FFMpeg Ruby Bridge. Call FFMpeg/LibAVCodec/LibAVFormat directly
|
|
17
|
+
email: ""
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions:
|
|
21
|
+
- ext/ffmpeg_ruby/extconf.rb
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- README.rdoc
|
|
24
|
+
- ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist
|
|
25
|
+
- ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest
|
|
26
|
+
- ext/ffmpeg_ruby/extconf.rb
|
|
27
|
+
- ext/ffmpeg_ruby/ffmpeg_avcodec.c
|
|
28
|
+
- ext/ffmpeg_ruby/ffmpeg_avcodec.h
|
|
29
|
+
- ext/ffmpeg_ruby/ffmpeg_avformat.c
|
|
30
|
+
- ext/ffmpeg_ruby/ffmpeg_avformat.h
|
|
31
|
+
- ext/ffmpeg_ruby/ffmpeg_ruby.c
|
|
32
|
+
- ext/ffmpeg_ruby/ffmpeg_ruby.h
|
|
33
|
+
- lib/ffmpeg-ruby.rb
|
|
34
|
+
- tasks/mac_specific.rake
|
|
35
|
+
files:
|
|
36
|
+
- Manifest
|
|
37
|
+
- README.rdoc
|
|
38
|
+
- Rakefile
|
|
39
|
+
- ext/ffmpeg_ruby/conftest.dSYM/Contents/Info.plist
|
|
40
|
+
- ext/ffmpeg_ruby/conftest.dSYM/Contents/Resources/DWARF/conftest
|
|
41
|
+
- ext/ffmpeg_ruby/extconf.rb
|
|
42
|
+
- ext/ffmpeg_ruby/ffmpeg_avcodec.c
|
|
43
|
+
- ext/ffmpeg_ruby/ffmpeg_avcodec.h
|
|
44
|
+
- ext/ffmpeg_ruby/ffmpeg_avformat.c
|
|
45
|
+
- ext/ffmpeg_ruby/ffmpeg_avformat.h
|
|
46
|
+
- ext/ffmpeg_ruby/ffmpeg_ruby.c
|
|
47
|
+
- ext/ffmpeg_ruby/ffmpeg_ruby.h
|
|
48
|
+
- ffmpeg-ruby.gemspec
|
|
49
|
+
- lib/ffmpeg-ruby.rb
|
|
50
|
+
- tasks/mac_specific.rake
|
|
51
|
+
- test/test.rb
|
|
52
|
+
has_rdoc: true
|
|
53
|
+
homepage: http://github.com/hackerdude/ffmpeg-ruby
|
|
54
|
+
licenses: []
|
|
55
|
+
|
|
56
|
+
post_install_message:
|
|
57
|
+
rdoc_options:
|
|
58
|
+
- --line-numbers
|
|
59
|
+
- --inline-source
|
|
60
|
+
- --title
|
|
61
|
+
- Ffmpeg-ruby
|
|
62
|
+
- --main
|
|
63
|
+
- README.rdoc
|
|
64
|
+
require_paths:
|
|
65
|
+
- lib
|
|
66
|
+
- ext
|
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: "0"
|
|
72
|
+
version:
|
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
|
+
requirements:
|
|
75
|
+
- - ">="
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: "1.2"
|
|
78
|
+
version:
|
|
79
|
+
requirements: []
|
|
80
|
+
|
|
81
|
+
rubyforge_project: ffmpeg-ruby
|
|
82
|
+
rubygems_version: 1.3.5
|
|
83
|
+
signing_key:
|
|
84
|
+
specification_version: 3
|
|
85
|
+
summary: FFMpeg Ruby Bridge. Call FFMpeg/LibAVCodec/LibAVFormat directly
|
|
86
|
+
test_files: []
|
|
87
|
+
|