ffmpeg-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|