ffi-ffmpeg 0.5.8135c9c5dc36
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/.hgignore +10 -0
- data/Gemfile +4 -0
- data/README.md +70 -0
- data/Rakefile +1 -0
- data/examples/extract_keyframes.rb +47 -0
- data/examples/read_file.rb +46 -0
- data/examples/seek.rb +49 -0
- data/ffi-ffmpeg.gemspec +26 -0
- data/lib/ffi-ffmpeg.rb +30 -0
- data/lib/ffi/ffmpeg.rb +629 -0
- data/lib/ffmpeg/frame.rb +58 -0
- data/lib/ffmpeg/reader.rb +74 -0
- data/lib/ffmpeg/stream.rb +244 -0
- data/lib/ffmpeg/version.rb +3 -0
- metadata +72 -0
data/.hgignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
ffi-ffmpeg
|
2
|
+
==========
|
3
|
+
http://github.com/dmlary/ffi-ffmpeg
|
4
|
+
|
5
|
+
Description
|
6
|
+
-----------
|
7
|
+
Ruby-FFI bindings and wrappers for FFmpeg libraries.
|
8
|
+
|
9
|
+
Features
|
10
|
+
--------
|
11
|
+
Right now this library only supports the reading of video streams.
|
12
|
+
|
13
|
+
What's missing
|
14
|
+
--------------
|
15
|
+
* Reading audio streams
|
16
|
+
* Execute ffmpeg cleanup when Reader, Stream, Frame instances are gc'ed
|
17
|
+
* Encoding
|
18
|
+
|
19
|
+
Usage
|
20
|
+
-----
|
21
|
+
ruby
|
22
|
+
require 'ffi-ffmpeg'
|
23
|
+
|
24
|
+
# Allocate a reader for our video file
|
25
|
+
reader = FFmpeg::Reader.new(ARGV[0], :pixel_format => :rgb24)
|
26
|
+
|
27
|
+
# Dump the format information for the file
|
28
|
+
reader.dump_format
|
29
|
+
|
30
|
+
# Grab the first video stream in the file
|
31
|
+
stream = reader.streams.select { |s| s.type == :video }.first
|
32
|
+
|
33
|
+
# Discard non-key frames
|
34
|
+
stream.discard = :nonkey
|
35
|
+
|
36
|
+
# Loop through the key frames for the first video stream
|
37
|
+
stream.each_frame do |frame|
|
38
|
+
# Do something interesting with the frame...
|
39
|
+
# pixel data is in frame.av_frame[:data]
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
Copyright
|
44
|
+
---------
|
45
|
+
Copyright (c) 2011, David M. Lary
|
46
|
+
All rights reserved.
|
47
|
+
|
48
|
+
License
|
49
|
+
-------
|
50
|
+
Redistribution and use in source and binary forms, with or without
|
51
|
+
modification, are permitted provided that the following conditions are met:
|
52
|
+
|
53
|
+
* Redistributions of source code must retain the above copyright
|
54
|
+
notice, this list of conditions and the following disclaimer.
|
55
|
+
* Redistributions in binary form must reproduce the above copyright
|
56
|
+
notice, this list of conditions and the following disclaimer in the
|
57
|
+
documentation and/or other materials provided with the distribution.
|
58
|
+
* The name of the author may not be used to endorse or promote products
|
59
|
+
derived from this software without specific prior written permission.
|
60
|
+
|
61
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
62
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
63
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
64
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
65
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
66
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
67
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
68
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
69
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
70
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
require 'ffi-ffmpeg'
|
5
|
+
|
6
|
+
def write_frame(filename, frame)
|
7
|
+
file = File.new(filename, "w")
|
8
|
+
file.write "P6\n%d %d\n255\n" % [frame.width, frame.height]
|
9
|
+
|
10
|
+
data = frame.av_frame[:data][0]
|
11
|
+
linesize = frame.av_frame[:linesize][0]
|
12
|
+
bytes_per_row = 3 * frame.width
|
13
|
+
|
14
|
+
frame.height.times do |row|
|
15
|
+
file.write data.slice(row * linesize, bytes_per_row)\
|
16
|
+
.read_string_length(bytes_per_row)
|
17
|
+
end
|
18
|
+
file.close
|
19
|
+
end
|
20
|
+
|
21
|
+
# Open our video file
|
22
|
+
reader = FFmpeg::Reader.new(ARGV[0], :pixel_format => :rgb24)
|
23
|
+
|
24
|
+
reader.dump_format
|
25
|
+
# Find the first video stream
|
26
|
+
stream = reader.streams.select { |s| s.discard = :all; s.type == :video } .first
|
27
|
+
|
28
|
+
# Tell the library to discard all non-key frames
|
29
|
+
stream.discard = :nonkey
|
30
|
+
|
31
|
+
# Write the first five key frames to disk
|
32
|
+
5.times do |i|
|
33
|
+
frame = stream.next_frame
|
34
|
+
write_frame("image-%d.ppm" % i, frame)
|
35
|
+
puts "wrote frame %d" % frame.number
|
36
|
+
end
|
37
|
+
|
38
|
+
stream.pixel_format = :gray8
|
39
|
+
|
40
|
+
# Write the first five key frames to disk
|
41
|
+
5.times do |i|
|
42
|
+
frame = stream.next_frame
|
43
|
+
scaled = frame.scale(:width => 100, :height => 100, :pixel_format => :rgb24)
|
44
|
+
write_frame("small-%d.ppm" % i, scaled)
|
45
|
+
puts "wrote small frame %d" % scaled.number
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
require 'ffi-ffmpeg'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
def format_seconds(s)
|
8
|
+
s = s.to_i
|
9
|
+
h = s/3600
|
10
|
+
s -= h * 3600
|
11
|
+
m = s/60
|
12
|
+
s -= m * 60
|
13
|
+
"%02d:%02d:%02d" % [ h, m, s ]
|
14
|
+
end
|
15
|
+
|
16
|
+
GLYPHS = %w{ | / - \\ }
|
17
|
+
@first = nil
|
18
|
+
@last = nil
|
19
|
+
@calls = 0
|
20
|
+
def spin(frame)
|
21
|
+
now = Time.now()
|
22
|
+
@first ||= now
|
23
|
+
@last ||= now
|
24
|
+
|
25
|
+
@calls += 1
|
26
|
+
|
27
|
+
if (@last + 0.25 < now)
|
28
|
+
fps = @calls.to_f / (now - @first)
|
29
|
+
pos = frame.number / frame.stream.fps.to_f
|
30
|
+
printf("\r[%s] %0.03f fps, frame: %d, pos: %s",
|
31
|
+
format_seconds(now - @first), fps, frame.number,
|
32
|
+
format_seconds(pos))
|
33
|
+
@last = now
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# open our video file
|
38
|
+
reader = FFmpeg::Reader.new(ARGV[0])
|
39
|
+
reader.dump_format
|
40
|
+
|
41
|
+
# Find the first video stream
|
42
|
+
reader.streams.each { |s| s.discard == :all }
|
43
|
+
stream = reader.default_stream
|
44
|
+
stream.discard = :default
|
45
|
+
# stream.buffer_size = 2
|
46
|
+
stream.each_frame { |frame| spin frame}
|
data/examples/seek.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
5
|
+
require 'ffi-ffmpeg'
|
6
|
+
|
7
|
+
def write_frame(filename, frame)
|
8
|
+
file = File.new(filename, "w")
|
9
|
+
file.write "P6\n%d %d\n255\n" % [frame.width, frame.height]
|
10
|
+
|
11
|
+
data = frame.av_frame[:data][0]
|
12
|
+
linesize = frame.av_frame[:linesize][0]
|
13
|
+
bytes_per_row = 3 * frame.width
|
14
|
+
|
15
|
+
frame.height.times do |row|
|
16
|
+
file.write data.slice(row * linesize, bytes_per_row)\
|
17
|
+
.read_string_length(bytes_per_row)
|
18
|
+
end
|
19
|
+
file.close
|
20
|
+
end
|
21
|
+
|
22
|
+
# Open our video file
|
23
|
+
reader = FFmpeg::Reader.new(ARGV[0], :pixel_format => :rgb24)
|
24
|
+
stream = reader.default_stream
|
25
|
+
|
26
|
+
# Find the first video stream
|
27
|
+
reader.streams.each { |s| s.discard = :all unless s == stream }
|
28
|
+
stream.discard = :nonkey
|
29
|
+
|
30
|
+
count = ARGV[1] ? ARGV[1].to_i : 10
|
31
|
+
step = File.size(ARGV[0]) / (count + 2)
|
32
|
+
|
33
|
+
count.times do |i|
|
34
|
+
i += 1
|
35
|
+
puts "Seeking to %d" % (i * step)
|
36
|
+
stream.seek(:pos => i * step)
|
37
|
+
|
38
|
+
frame = stream.next_frame
|
39
|
+
|
40
|
+
# For some reason, when working on MPEG-TS files, following the seek,
|
41
|
+
# the packet DTS of the next packet read is -1 * AV_NOPTS_VALUE. When
|
42
|
+
# we save that frame it looks like a stale buffer. So we want to skip
|
43
|
+
# the frame if the pts is this value. Also only accept key frames.
|
44
|
+
until frame.key_frame? and frame.pts != -1 * FFI::FFmpeg::AV_NOPTS_VALUE
|
45
|
+
frame = stream.next_frame
|
46
|
+
end
|
47
|
+
puts "Saving frame %d, pts %d" % [ frame.number, frame.pts ]
|
48
|
+
write_frame("seek-%02d.ppm" % i, frame)
|
49
|
+
end
|
data/ffi-ffmpeg.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ffi-ffmpeg"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ffi-ffmpeg"
|
7
|
+
s.version = "%s.%s" % [ FFmpeg::VERSION,
|
8
|
+
`hg id -i`.chomp.sub("+", "m") ]
|
9
|
+
s.authors = ["David M. Lary"]
|
10
|
+
s.email = ["dmlary@gmail.com"]
|
11
|
+
s.homepage = "http://bitbucket.com/dmlary/ffi-ffmpeg"
|
12
|
+
s.summary = %q{Ruby FFI bindings for FFmpeg libraries}
|
13
|
+
s.description = %q{Ruby FFI bindings for FFmpeg libraries:
|
14
|
+
* libavformat
|
15
|
+
* libavcodec
|
16
|
+
* libavutil
|
17
|
+
* libswscale}
|
18
|
+
|
19
|
+
s.rubyforge_project = "ffi-ffmpeg"
|
20
|
+
|
21
|
+
s.files = `hg locate`.split("\n")
|
22
|
+
s.test_files = `hg locate -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `hg locate -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
s.add_dependency "ffi"
|
26
|
+
end
|
data/lib/ffi-ffmpeg.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "ffi/ffmpeg"
|
2
|
+
require "ffmpeg/version"
|
3
|
+
require "ffmpeg/frame"
|
4
|
+
require "ffmpeg/stream"
|
5
|
+
require "ffmpeg/reader"
|
6
|
+
|
7
|
+
module FFmpeg
|
8
|
+
|
9
|
+
# Get the logging level
|
10
|
+
def self.log_level
|
11
|
+
FFI::FFmpeg.av_log_get_level
|
12
|
+
end
|
13
|
+
|
14
|
+
# Set the logging level
|
15
|
+
#
|
16
|
+
# [:level] Logging level in FFI::FFMpeg::AVLogLevel
|
17
|
+
#
|
18
|
+
def self.log_level=(level)
|
19
|
+
FFI::FFmpeg.av_log_set_level level
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
@@registered_all = false
|
25
|
+
def self.register_all
|
26
|
+
return if @@registered_all
|
27
|
+
FFI::FFmpeg.av_register_all
|
28
|
+
@@registered_all = true
|
29
|
+
end
|
30
|
+
end
|
data/lib/ffi/ffmpeg.rb
ADDED
@@ -0,0 +1,629 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module FFmpeg
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
AV_NOPTS_VALUE = 0x8000000000000000
|
8
|
+
|
9
|
+
ffi_lib "libavutil.so.49"
|
10
|
+
|
11
|
+
AVMediaType = enum :unknown, -1,
|
12
|
+
:video,
|
13
|
+
:audio,
|
14
|
+
:data,
|
15
|
+
:subtitle,
|
16
|
+
:attachment
|
17
|
+
|
18
|
+
BIG_ENDIAN = [1].pack("I") == [1].pack("N")
|
19
|
+
PixelFormat = enum :none, -1,
|
20
|
+
:yuv420p,
|
21
|
+
:yuyv422,
|
22
|
+
:rgb24,
|
23
|
+
:bgr24,
|
24
|
+
:yuv422p,
|
25
|
+
:yuv444p,
|
26
|
+
:yuv410p,
|
27
|
+
:yuv411p,
|
28
|
+
:gray8,
|
29
|
+
:monowhite,
|
30
|
+
:monoblack,
|
31
|
+
:pal8,
|
32
|
+
:yuvj420p,
|
33
|
+
:yuvj422p,
|
34
|
+
:yuvj444p,
|
35
|
+
:xvmc_mpeg2_mc,
|
36
|
+
:xvmc_mpeg2_idct,
|
37
|
+
:uyvy422,
|
38
|
+
:uyyvyy411,
|
39
|
+
:bgr8,
|
40
|
+
:bgr4,
|
41
|
+
:bgr4_byte,
|
42
|
+
:rgb8,
|
43
|
+
:rgb4,
|
44
|
+
:rgb4_byte,
|
45
|
+
:nv12,
|
46
|
+
:nv21,
|
47
|
+
BIG_ENDIAN ? :rgb32 : :bgr32_1, # :argb
|
48
|
+
BIG_ENDIAN ? :rgb32_1 : :bgr32, # :rgba
|
49
|
+
BIG_ENDIAN ? :bgr32 : :rgb32_1, # :abgr
|
50
|
+
BIG_ENDIAN ? :bgr32_1 : :rgb32, # :bgra
|
51
|
+
BIG_ENDIAN ? :gray16 : :gray16_1, # :gray16be
|
52
|
+
BIG_ENDIAN ? :gray16_1 : :gray16, # :gray16le
|
53
|
+
:yuv440p,
|
54
|
+
:yuvj440p,
|
55
|
+
:yuva420p,
|
56
|
+
:vdpau_h264,
|
57
|
+
:vdpau_mpeg1,
|
58
|
+
:vdpau_mpeg2,
|
59
|
+
:vdpau_wmv3,
|
60
|
+
:vdpau_vc1,
|
61
|
+
BIG_ENDIAN ? :rgb48 : :rgb48_1, # :rgb48be
|
62
|
+
BIG_ENDIAN ? :rgb48_1 : :rgb48, # :rgb48le
|
63
|
+
BIG_ENDIAN ? :rgb565 : :rgb565_1, # :rgb565be
|
64
|
+
BIG_ENDIAN ? :rgb565_1 : :rgb565, # :rgb565le
|
65
|
+
BIG_ENDIAN ? :rgb555 : :rgb555_1, # :rgb555be
|
66
|
+
BIG_ENDIAN ? :rgb555_1 : :rgb555, # :rgb555le
|
67
|
+
BIG_ENDIAN ? :bgr565 : :bgr565_1, # :bgr565be
|
68
|
+
BIG_ENDIAN ? :bgr565_1 : :bgr565, # :bgr565le
|
69
|
+
BIG_ENDIAN ? :bgr555 : :bgr555_1, # :bgr555be
|
70
|
+
BIG_ENDIAN ? :bgr555_1 : :bgr555, # :bgr555le
|
71
|
+
:vaapi_moco,
|
72
|
+
:vaapi_idct,
|
73
|
+
:vaapi_vld,
|
74
|
+
BIG_ENDIAN ? :yuv420p16_1 : :yuv420p16, # :yuv420p16le
|
75
|
+
BIG_ENDIAN ? :yuv420p16 : :yuv420p16_1, # :yuv420p16be
|
76
|
+
BIG_ENDIAN ? :yuv422p16_1 : :yuv422p16, # :yuv422p16le
|
77
|
+
BIG_ENDIAN ? :yuv422p16 : :yuv422p16_1, # :yuv422p16be
|
78
|
+
BIG_ENDIAN ? :yuv444p16_1 : :yuv444p16, # :yuv444p16le
|
79
|
+
BIG_ENDIAN ? :yuv444p16 : :yuv444p16_1, # :yuv444p16be
|
80
|
+
:vdpau_mpeg4,
|
81
|
+
:dxva2_vld,
|
82
|
+
BIG_ENDIAN ? :rgb444 : :rgb444_1, # :rgb444be
|
83
|
+
BIG_ENDIAN ? :rgb444_1 : :rgb444, # :rgb444le
|
84
|
+
BIG_ENDIAN ? :bgr444 : :bgr444_1, # :bgr444be
|
85
|
+
BIG_ENDIAN ? :bgr444_1 : :bgr444, # :bgr444le
|
86
|
+
:y400a
|
87
|
+
|
88
|
+
# Not actually an enum in libavutil.h, but we make it one here to
|
89
|
+
# make the api prettier.
|
90
|
+
AVLogLevel = enum :quiet, -8,
|
91
|
+
:panic, 0,
|
92
|
+
:fatal, 8,
|
93
|
+
:error, 16,
|
94
|
+
:warning, 24,
|
95
|
+
:info, 32,
|
96
|
+
:verbose, 40,
|
97
|
+
:debug, 48
|
98
|
+
|
99
|
+
attach_function :av_log_get_level, [], AVLogLevel
|
100
|
+
attach_function :av_log_set_level, [AVLogLevel], :void
|
101
|
+
attach_function :av_free, [:pointer], :void
|
102
|
+
attach_function :av_malloc, [:uint], :pointer
|
103
|
+
|
104
|
+
ffi_lib "libavformat.so.52"
|
105
|
+
|
106
|
+
MAX_STREAMS = 20
|
107
|
+
MAX_REORDER_DELAY = 16
|
108
|
+
|
109
|
+
AVSEEK_FLAG_BACKWARD = 1
|
110
|
+
AVSEEK_FLAG_BYTE = 2
|
111
|
+
AVSEEK_FLAG_ANY = 4
|
112
|
+
|
113
|
+
attach_function :av_register_all, [], :void
|
114
|
+
attach_function :av_open_input_file,
|
115
|
+
[:pointer, :string, :pointer, :int, :pointer],
|
116
|
+
:int
|
117
|
+
attach_function :av_find_stream_info, [:pointer], :int
|
118
|
+
attach_function :dump_format,
|
119
|
+
[:pointer, :int, :string, :int],
|
120
|
+
:void
|
121
|
+
attach_function :av_read_frame, [:pointer, :pointer], :int
|
122
|
+
attach_function :av_seek_frame, [:pointer, :int, :long_long, :int], :int
|
123
|
+
attach_function :av_find_default_stream_index, [ :pointer ], :int
|
124
|
+
|
125
|
+
# Defining this manually since it's a static inline:
|
126
|
+
#
|
127
|
+
# static inline void av_free_packet(AVPacket *pkt)
|
128
|
+
# {
|
129
|
+
# if (pkt && pkt->destruct) {
|
130
|
+
# pkt->destruct(pkt);
|
131
|
+
# }
|
132
|
+
# }
|
133
|
+
#
|
134
|
+
def self.av_free_packet(pkt)
|
135
|
+
return unless pkt and pkt[:destruct]
|
136
|
+
|
137
|
+
FFI::Function.new(:void, [:pointer], pkt[:destruct],
|
138
|
+
:blocking => true).call(pkt)
|
139
|
+
end
|
140
|
+
|
141
|
+
def av_free_packet(pkt)
|
142
|
+
FFI::FFmpeg.av_free_packet(pkt)
|
143
|
+
end
|
144
|
+
|
145
|
+
ffi_lib "libavcodec.so.52"
|
146
|
+
AV_PARSER_PTS_NB = 4
|
147
|
+
|
148
|
+
AVDiscard = enum :none, -16,
|
149
|
+
:default, 0,
|
150
|
+
:nonref, 8,
|
151
|
+
:bidir, 16,
|
152
|
+
:nonkey, 32,
|
153
|
+
:all, 48
|
154
|
+
|
155
|
+
attach_function :avcodec_find_decoder, [:int], :pointer
|
156
|
+
attach_function :avcodec_open, [:pointer, :pointer], :int
|
157
|
+
attach_function :avcodec_alloc_frame, [], :pointer
|
158
|
+
attach_function :avpicture_get_size, [PixelFormat, :int, :int], :int
|
159
|
+
attach_function :avpicture_fill,
|
160
|
+
[:pointer, :pointer, PixelFormat, :int, :int],
|
161
|
+
:int
|
162
|
+
attach_function :avcodec_decode_video, [:pointer, :pointer, :pointer,
|
163
|
+
:pointer, :int], :int,
|
164
|
+
{ :blocking => true }
|
165
|
+
attach_function :avcodec_default_get_buffer, [:pointer, :pointer], :int
|
166
|
+
attach_function :avcodec_default_release_buffer, [:pointer, :pointer], :int
|
167
|
+
|
168
|
+
ffi_lib "libswscale.so.0"
|
169
|
+
SWScaleFlags = enum :fast_bilinear, 0x001,
|
170
|
+
:bilinear, 0x002,
|
171
|
+
:bicubic, 0x004,
|
172
|
+
:x, 0x008,
|
173
|
+
:point, 0x010,
|
174
|
+
:area, 0x020,
|
175
|
+
:bicublin, 0x040,
|
176
|
+
:gauss, 0x080,
|
177
|
+
:sinc, 0x100,
|
178
|
+
:lanczos, 0x200,
|
179
|
+
:spline, 0x400
|
180
|
+
|
181
|
+
attach_function :sws_getContext,
|
182
|
+
[:int, :int, PixelFormat, :int, :int, PixelFormat,
|
183
|
+
SWScaleFlags, :pointer, :pointer, :pointer],
|
184
|
+
:pointer
|
185
|
+
attach_function :sws_freeContext,
|
186
|
+
[:pointer],
|
187
|
+
:void
|
188
|
+
attach_function :sws_scale,
|
189
|
+
[:pointer, :pointer, :pointer, :int,
|
190
|
+
:int, :pointer, :pointer],
|
191
|
+
:int,
|
192
|
+
{ :blocking => true }
|
193
|
+
|
194
|
+
|
195
|
+
class AVRational < FFI::Struct
|
196
|
+
layout :num, :int,
|
197
|
+
:den, :int
|
198
|
+
|
199
|
+
def to_f
|
200
|
+
self[:num].to_f / self[:den]
|
201
|
+
end
|
202
|
+
|
203
|
+
def to_float
|
204
|
+
to_f
|
205
|
+
end
|
206
|
+
|
207
|
+
def to_i
|
208
|
+
self[:num] / self[:den]
|
209
|
+
end
|
210
|
+
|
211
|
+
def to_s
|
212
|
+
"#<AVRational:0x%016x num=%d, den=%d, %f>" %
|
213
|
+
[object_id, self[:num], self[:den], to_f]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class AVFrac < FFI::Struct
|
218
|
+
layout :val, :long_long,
|
219
|
+
:num, :long_long,
|
220
|
+
:den, :long_long
|
221
|
+
|
222
|
+
def to_f
|
223
|
+
self[:val] + self[:num].to_f / self[:den]
|
224
|
+
end
|
225
|
+
|
226
|
+
def to_i
|
227
|
+
self[:val] + self[:num] / self[:den]
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_s
|
231
|
+
"#<AVRational:0x%016x val=%d, num=%d, den=%d, %f>" %
|
232
|
+
[object_id, self[:val], self[:num], self[:den], to_f]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class AVProbeData < FFI::Struct
|
237
|
+
layout :filename, :string,
|
238
|
+
:buf, :pointer,
|
239
|
+
:buf_size, :int
|
240
|
+
end
|
241
|
+
|
242
|
+
class AVPacket < FFI::Struct
|
243
|
+
layout :pts, :long,
|
244
|
+
:dts, :long,
|
245
|
+
:data, :pointer,
|
246
|
+
:size, :int,
|
247
|
+
:stream_index, :int,
|
248
|
+
:flags, :int,
|
249
|
+
:duration, :int,
|
250
|
+
:destruct, :pointer,
|
251
|
+
:priv, :pointer,
|
252
|
+
:pos, :long,
|
253
|
+
:convergence_duration, :long
|
254
|
+
end
|
255
|
+
|
256
|
+
class AVPacketList < FFI::Struct
|
257
|
+
layout :pkt, AVPacket,
|
258
|
+
:next, :pointer
|
259
|
+
end
|
260
|
+
|
261
|
+
class AVStream < FFI::Struct
|
262
|
+
layout :index, :int,
|
263
|
+
:id, :int,
|
264
|
+
:codec, :pointer,
|
265
|
+
:r_frame_rate, AVRational,
|
266
|
+
:priv_data, :pointer,
|
267
|
+
:first_dts, :long_long,
|
268
|
+
:pts, AVFrac,
|
269
|
+
:time_base, AVRational,
|
270
|
+
:pts_wrap_bits, :int,
|
271
|
+
:stream_copy, :int,
|
272
|
+
:discard, AVDiscard,
|
273
|
+
:quality, :float,
|
274
|
+
:start_time, :long_long,
|
275
|
+
:duration, :long_long,
|
276
|
+
:language, [:char, 4],
|
277
|
+
:need_parsing, :int, # enum AVStreamParseType,
|
278
|
+
:parser, :pointer,
|
279
|
+
:cur_dts, :long_long,
|
280
|
+
:last_IP_duration, :int,
|
281
|
+
:last_IP_pts, :long_long,
|
282
|
+
:index_entries, :pointer,
|
283
|
+
:nb_index_entries, :int,
|
284
|
+
:index_entries_allocated_size, :uint,
|
285
|
+
:nb_frames, :long_long,
|
286
|
+
:unused, [:long_long, 5],
|
287
|
+
:filename, :string,
|
288
|
+
:disposition, :int,
|
289
|
+
:probe_data, AVProbeData,
|
290
|
+
:pts_buffer, [:long_long, MAX_REORDER_DELAY + 1],
|
291
|
+
:sample_aspect_ratio, AVRational,
|
292
|
+
:metadata, :pointer,
|
293
|
+
:cur_ptr, :pointer,
|
294
|
+
:cur_len, :int,
|
295
|
+
:cur_pkt, AVPacket,
|
296
|
+
:reference_dts, :long_long,
|
297
|
+
:probe_packets, :int,
|
298
|
+
:last_in_packet_butter, AVPacketList,
|
299
|
+
:avg_frame_rate, AVRational,
|
300
|
+
:codec_info_nb_frames, :int
|
301
|
+
|
302
|
+
def codec
|
303
|
+
AVCodecContext.new send(:[], :codec)
|
304
|
+
end
|
305
|
+
|
306
|
+
def to_s
|
307
|
+
'#<AVStream:0x%08x index=%d, id=%d, codec_type=:%s>' %
|
308
|
+
[ object_id, self[:index], self[:id], codec[:codec_type] ]
|
309
|
+
end
|
310
|
+
|
311
|
+
def discard=(type)
|
312
|
+
send(:[]=, :discard, type)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
callback :av_codec_context_get_buffer, [:pointer, :pointer], :int
|
317
|
+
|
318
|
+
class AVCodecContext < FFI::Struct
|
319
|
+
layout :av_class, :pointer,
|
320
|
+
:bit_rate, :int,
|
321
|
+
:bit_rate_rolerance, :int,
|
322
|
+
:flags, :int,
|
323
|
+
:sub_id, :int,
|
324
|
+
:me_method, :int,
|
325
|
+
:extradata, :pointer,
|
326
|
+
:extradata_size, :int,
|
327
|
+
:time_base, AVRational,
|
328
|
+
:width, :int,
|
329
|
+
:height, :int,
|
330
|
+
:gop_size, :int,
|
331
|
+
:pix_fmt, PixelFormat,
|
332
|
+
:rate_emu, :int,
|
333
|
+
:draw_horiz_band, :pointer,
|
334
|
+
:sample_rate, :int,
|
335
|
+
:channels, :int,
|
336
|
+
:sample_fmt, :int, # TODO enum SampleFormat
|
337
|
+
:frame_size, :int,
|
338
|
+
:frame_number, :int,
|
339
|
+
:real_pict_num, :int,
|
340
|
+
:delay, :int,
|
341
|
+
:qcompress, :float,
|
342
|
+
:qblur, :float,
|
343
|
+
:qmin, :int,
|
344
|
+
:qmax, :int,
|
345
|
+
:max_qdiff, :int,
|
346
|
+
:max_b_frames, :int,
|
347
|
+
:b_quant_factor, :float,
|
348
|
+
:rc_strategy, :int,
|
349
|
+
:b_frame_strategy, :int,
|
350
|
+
:hurry_up, :int,
|
351
|
+
:codec, :pointer,
|
352
|
+
:priv_data, :pointer,
|
353
|
+
:rtp_payload_size, :int,
|
354
|
+
:rtp_callback, :pointer,
|
355
|
+
:mv_bits, :int,
|
356
|
+
:header_bits, :int,
|
357
|
+
:i_tex_bits, :int,
|
358
|
+
:p_tex_bits, :int,
|
359
|
+
:i_count, :int,
|
360
|
+
:p_count, :int,
|
361
|
+
:skip_count, :int,
|
362
|
+
:misc_bits, :int,
|
363
|
+
:frame_bits, :int,
|
364
|
+
:opaque, :pointer,
|
365
|
+
:codec_name, [:char, 32],
|
366
|
+
:codec_type, AVMediaType,
|
367
|
+
:codec_id, :int, # TODO enum CodecID
|
368
|
+
:codec_tag, :uint,
|
369
|
+
:workaround_bugs, :int,
|
370
|
+
:luma_elim_threshold, :int,
|
371
|
+
:chroma_elim_threshold, :int,
|
372
|
+
:strict_std_compliance, :int,
|
373
|
+
:b_quant_offset, :float,
|
374
|
+
:error_recognition, :int,
|
375
|
+
:get_buffer, :av_codec_context_get_buffer,
|
376
|
+
:release_buffer, :pointer,
|
377
|
+
:has_b_frames, :int,
|
378
|
+
:block_align, :int,
|
379
|
+
:parse_only, :int,
|
380
|
+
:mpeg_quant, :int,
|
381
|
+
:stats_out, :pointer,
|
382
|
+
:stats_in, :pointer,
|
383
|
+
:rc_qsquish, :float,
|
384
|
+
:rc_qmod_amp, :float,
|
385
|
+
:rc_qmod_freq, :int,
|
386
|
+
:rc_override, :pointer,
|
387
|
+
:rc_override_count, :int,
|
388
|
+
:rc_eq, :pointer,
|
389
|
+
:rc_max_rate, :int,
|
390
|
+
:rc_min_rate, :int,
|
391
|
+
:rc_buffer_size, :int,
|
392
|
+
:rc_buffer_aggressivity, :float,
|
393
|
+
:i_quant_factor, :float,
|
394
|
+
:i_quant_offset, :float,
|
395
|
+
:rc_initial_cplx, :float,
|
396
|
+
:dct_algo, :int,
|
397
|
+
:lumi_masking, :float,
|
398
|
+
:temporal_cplx_masking, :float,
|
399
|
+
:spatial_cplx_masking, :float,
|
400
|
+
:p_masking, :float,
|
401
|
+
:dark_masking, :float,
|
402
|
+
:idct_algo, :int,
|
403
|
+
:splice_count, :int,
|
404
|
+
:slice_offset, :pointer,
|
405
|
+
:error_concealment, :int,
|
406
|
+
:dsp_mask, :uint,
|
407
|
+
:bits_per_coded_sample, :int,
|
408
|
+
:prediction_method, :int,
|
409
|
+
:sample_aspect_ratio, AVRational,
|
410
|
+
:coded_frame, :pointer,
|
411
|
+
:debug, :int,
|
412
|
+
:debug_mv, :int,
|
413
|
+
:error, [:ulong_long, 4],
|
414
|
+
:mb_qmin, :int,
|
415
|
+
:mb_qmax, :int,
|
416
|
+
:me_cmp, :int,
|
417
|
+
:me_sub_cmp, :int,
|
418
|
+
:ildct_cmp, :int,
|
419
|
+
:dia_size, :int,
|
420
|
+
:last_predictor_count, :int,
|
421
|
+
:pre_me, :int,
|
422
|
+
:me_pre_cmp, :int,
|
423
|
+
:pre_dia_size, :int,
|
424
|
+
:me_subpel_quality, :int,
|
425
|
+
:get_format, :pointer,
|
426
|
+
:dtg_active_format, :int,
|
427
|
+
:me_range, :int,
|
428
|
+
:intra_quant_bias, :int,
|
429
|
+
:inter_quant_bias, :int,
|
430
|
+
:color_table_id, :int,
|
431
|
+
:internal_buffer_count, :int,
|
432
|
+
:internal_buffer, :pointer,
|
433
|
+
:global_quality, :int,
|
434
|
+
:coder_type, :int,
|
435
|
+
:context_model, :int,
|
436
|
+
:slice_flags, :int,
|
437
|
+
:xvmc_acceleration, :int,
|
438
|
+
:mb_decision, :int,
|
439
|
+
:intra_matrix, :pointer,
|
440
|
+
:inter_matrix, :pointer,
|
441
|
+
:stream_codec_tag, :int,
|
442
|
+
:scenechange_threshold, :int,
|
443
|
+
:lmin, :int,
|
444
|
+
:lmax, :int,
|
445
|
+
:palctrl, :pointer,
|
446
|
+
:noise_reduction, :int,
|
447
|
+
:reget_buffer, :pointer,
|
448
|
+
:rc_initial_buffer_occupancy, :int,
|
449
|
+
:inter_threshold, :int,
|
450
|
+
:flags2, :int,
|
451
|
+
:error_rate, :int,
|
452
|
+
:antialias_algo, :int,
|
453
|
+
:quantizer_noise_shaping, :int,
|
454
|
+
:thread_count, :int,
|
455
|
+
:execute, :pointer,
|
456
|
+
:thread_opaque, :pointer,
|
457
|
+
:me_threshold, :int,
|
458
|
+
:mb_threshold, :int,
|
459
|
+
:intra_dc_precision, :int,
|
460
|
+
:nsse_weight, :int,
|
461
|
+
:skip_top, :int,
|
462
|
+
:skip_bottom, :int,
|
463
|
+
:profile, :int,
|
464
|
+
:level, :int,
|
465
|
+
:lowres, :int,
|
466
|
+
:coded_width, :int,
|
467
|
+
:coded_height, :int,
|
468
|
+
:frame_skip_threshold, :int,
|
469
|
+
:frame_skip_factor, :int,
|
470
|
+
:frame_skip_cmp, :int,
|
471
|
+
:border_masking, :float,
|
472
|
+
:mb_lmin, :int,
|
473
|
+
:mb_lmax, :int,
|
474
|
+
:me_penalty_compensation, :int,
|
475
|
+
:skip_loop_filter, :int, # TODO enum AVDiscard
|
476
|
+
:skip_idct, :int, # TODO enum AVDiscard
|
477
|
+
:skip_frame, :int, # TODO enum AVDiscard
|
478
|
+
:bidir_refine, :int,
|
479
|
+
:brd_scale, :int,
|
480
|
+
:crf, :float,
|
481
|
+
:cqp, :int,
|
482
|
+
:keyint_min, :int,
|
483
|
+
:refs, :int,
|
484
|
+
:chromaoffset, :int,
|
485
|
+
:bframebias, :int,
|
486
|
+
:trellis, :int,
|
487
|
+
:complexityblur, :float,
|
488
|
+
:deblockalpha, :int,
|
489
|
+
:deblockbeta, :int,
|
490
|
+
:partitions, :int,
|
491
|
+
:directpred, :int,
|
492
|
+
:cutoff, :int,
|
493
|
+
:scenechange_factor, :int,
|
494
|
+
:mv0_threshold, :int,
|
495
|
+
:b_sensitivity, :int,
|
496
|
+
:compression_level, :int,
|
497
|
+
:use_lpc, :int,
|
498
|
+
:lpc_coeff_precision, :int,
|
499
|
+
:min_prediction_order, :int,
|
500
|
+
:max_prediction_order, :int,
|
501
|
+
:prediction_order_method, :int,
|
502
|
+
:min_partition_order, :int,
|
503
|
+
:max_partition_order, :int,
|
504
|
+
:timecode_frame_start, :long_long,
|
505
|
+
:request_channel, :int,
|
506
|
+
:drc_scale, :float,
|
507
|
+
:reordered_opaque, :long_long,
|
508
|
+
:bits_per_raw_sample, :int,
|
509
|
+
:channel_layout, :long_long,
|
510
|
+
:request_channel_layout, :long_long,
|
511
|
+
:rc_max_available_vbv_use, :float,
|
512
|
+
:rc_min_vbv_overflow_use, :float,
|
513
|
+
:hwaccel, :pointer,
|
514
|
+
:ticks_per_frame, :int,
|
515
|
+
:hwaccel_context, :pointer,
|
516
|
+
:color_primaries, :int, # enum AVColorPrimaries
|
517
|
+
:color_trc, :int, # enum AVColorTransferCharacteristic
|
518
|
+
:colorspace, :int, # enum AVColorSpace
|
519
|
+
:color_range, :int, # enum AVColorRange
|
520
|
+
:chroma_sample_location, :int,# enum AVChromaLocation
|
521
|
+
:execute2, :pointer,
|
522
|
+
:weighted_p_pred, :int,
|
523
|
+
:aq_mode, :int,
|
524
|
+
:aq_strength, :float,
|
525
|
+
:psy_rd, :float,
|
526
|
+
:psy_trellis, :float,
|
527
|
+
:rc_lookahead, :int
|
528
|
+
# LONGEST STRUCTURE EVER!!!!
|
529
|
+
end
|
530
|
+
|
531
|
+
class AVFormatContext < FFI::Struct
|
532
|
+
layout :av_class, :pointer,
|
533
|
+
:iformat, :pointer,
|
534
|
+
:oformat, :pointer,
|
535
|
+
:priv_data, :pointer,
|
536
|
+
:pb, :pointer,
|
537
|
+
:nb_streams, :uint,
|
538
|
+
:streams, [:pointer, MAX_STREAMS],
|
539
|
+
:filename, [:char, 1024],
|
540
|
+
:timestamp, :long_long,
|
541
|
+
:title, [:char, 512],
|
542
|
+
:author, [:char, 512],
|
543
|
+
:copyright, [:char, 512],
|
544
|
+
:comment, [:char, 512],
|
545
|
+
:album, [:char, 512],
|
546
|
+
:year, :int,
|
547
|
+
:track, :int,
|
548
|
+
:genre, [:char, 32],
|
549
|
+
:ctx_flags, :int,
|
550
|
+
:packet_buffer, :pointer,
|
551
|
+
:start_time, :long_long,
|
552
|
+
:duration, :long_long,
|
553
|
+
:file_size, :long_long,
|
554
|
+
:bitrate, :int,
|
555
|
+
:cur_st, :pointer,
|
556
|
+
:cur_ptr_deprecated, :pointer,
|
557
|
+
:cur_len_deprecated, :int,
|
558
|
+
:cur_pkt_deprecated, AVPacket,
|
559
|
+
:data_offset, :long_long,
|
560
|
+
:index_build, :int,
|
561
|
+
:mux_rate, :int,
|
562
|
+
:packet_size, :uint,
|
563
|
+
:max_delay, :int,
|
564
|
+
:loop_output, :int,
|
565
|
+
:flags, :int,
|
566
|
+
:loop_input, :int,
|
567
|
+
:probesize, :uint,
|
568
|
+
:max_analyze_diration, :int,
|
569
|
+
:key, :pointer,
|
570
|
+
:keylen, :int,
|
571
|
+
:nb_programs, :uint,
|
572
|
+
:programs, :pointer,
|
573
|
+
:video_codec_id, :uint, # enum CodecID
|
574
|
+
:audio_codec_id, :uint, # enum CodecID
|
575
|
+
:subtitle_codec_id, :uint, # enum CodecID
|
576
|
+
:max_index_size, :uint,
|
577
|
+
:max_picture_buffer, :uint,
|
578
|
+
:nb_chapters, :uint,
|
579
|
+
:chapters, :pointer,
|
580
|
+
:debug, :int,
|
581
|
+
:raw_packet_buffer, :pointer,
|
582
|
+
:raw_packet_buffer_end, :pointer,
|
583
|
+
:packet_buffet_end, :pointer,
|
584
|
+
:metadata, :pointer,
|
585
|
+
:raw_packet_buffer_remaining_size, :int,
|
586
|
+
:start_time_realtime, :long_long
|
587
|
+
end
|
588
|
+
|
589
|
+
class AVPicture < FFI::Struct
|
590
|
+
layout :data, [:pointer, 4],
|
591
|
+
:linesize, [:int, 4]
|
592
|
+
end
|
593
|
+
|
594
|
+
class AVFrame < FFI::Struct
|
595
|
+
layout :data, [:pointer, 4],
|
596
|
+
:linesize, [:int, 4],
|
597
|
+
:base, [:pointer, 4],
|
598
|
+
:key_frame, :int,
|
599
|
+
:pict_type, :int,
|
600
|
+
:pts, :int64,
|
601
|
+
:coded_picture_number, :int,
|
602
|
+
:dispay_picture_number, :int,
|
603
|
+
:quality, :int,
|
604
|
+
:age, :int,
|
605
|
+
:reference, :int,
|
606
|
+
:qscale_table, :pointer,
|
607
|
+
:qstride, :int,
|
608
|
+
:mbskip_table, :pointer,
|
609
|
+
:motion_val, [:pointer, 2],
|
610
|
+
:mb_type, :pointer,
|
611
|
+
:motion_subsample_log2, :uint8,
|
612
|
+
:opaque, :pointer,
|
613
|
+
:error, [:uint64, 4],
|
614
|
+
:type, :int,
|
615
|
+
:repeat_pict, :int,
|
616
|
+
:qscale_type, :int,
|
617
|
+
:interlaced_frame, :int,
|
618
|
+
:top_field_first, :int,
|
619
|
+
:pan_scan, :pointer,
|
620
|
+
:palette_has_changed, :int,
|
621
|
+
:buffer_hints, :int,
|
622
|
+
:dct_coeff, :pointer,
|
623
|
+
:ref_index, [:pointer, 2],
|
624
|
+
:reordered_opaque, :long_long
|
625
|
+
end
|
626
|
+
|
627
|
+
|
628
|
+
end # module FFmpeg
|
629
|
+
end # module FFI
|