Permalink
Browse files

Checkpoint for implementing audio decoding

  • Loading branch information...
1 parent 8bf8fd2 commit b456ea3ff4967170f680b682aaf0b32c1288c740 @drbrain committed Sep 3, 2009
Showing with 117 additions and 55 deletions.
  1. +2 −2 lib/ffmpeg/codec_context.rb
  2. +98 −44 lib/ffmpeg/format_context.rb
  3. +7 −3 lib/ffmpeg/packet.rb
  4. +10 −6 sample/transcode.rb
@@ -263,11 +263,11 @@ class FFMPEG::CodecContext
builder.accessor :pix_fmt, 'int'
builder.accessor :rc_buffer_size, 'int'
builder.accessor :rc_initial_buffer_occupancy, 'int'
+ builder.accessor :sample_rate, 'int'
builder.accessor :width, 'int'
builder.reader :channels, 'int'
builder.reader :_codec_type, 'int', :codec_type
- builder.reader :sample_rate, 'int'
builder.reader :sample_fmt, 'int'
builder.reader :codec_name, 'char *'
@@ -277,7 +277,7 @@ class << self
private :new
end
- alias :pixel_format :pix_fmt
+ alias pixel_format pix_fmt
def initialize(stream=nil)
@stream = stream
@@ -2,8 +2,6 @@ class FFMPEG::FormatContext
DTS_DELTA_THRESHOLD = 10
- attr_accessor :sync_pts
-
inline :C do |builder|
FFMPEG.builder_defaults builder
@@ -130,11 +128,43 @@ class FFMPEG::FormatContext
builder.c <<-C
VALUE output_format() {
- VALUE format_klass;
+ VALUE format_klass, obj;
+ AVFormatContext* format_context;
+ AVOutputFormat* output_format;
format_klass = rb_path2class("FFMPEG::OutputFormat");
- return rb_funcall(format_klass, rb_intern("from"), 1, self);
+ Data_Get_Struct(self, AVFormatContext, format_context);
+
+ if (format_context->oformat) {
+ obj = Data_Wrap_Struct(format_klass, NULL, NULL,
+ format_context->oformat);
+ } else {
+ obj = rb_funcall(format_klass, rb_intern("from"), 1, self);
+
+ Data_Get_Struct(obj, AVOutputFormat, output_format);
+
+ format_context->oformat = output_format;
+ }
+
+ return obj;
+ }
+ C
+
+ ##
+ # :method: output_format=
+
+ builder.c <<-C
+ VALUE output_format_equals(VALUE _output_format) {
+ AVFormatContext *format_context;
+ AVOutputFormat *output_format;
+
+ Data_Get_Struct(self, AVFormatContext, format_context);
+ Data_Get_Struct(_output_format, AVOutputFormat, output_format);
+
+ format_context->oformat = output_format;
+
+ return self;
}
C
@@ -230,23 +260,6 @@ class FFMPEG::FormatContext
C
##
- # :method: oformat=
-
- builder.c <<-C
- VALUE oformat_equals(VALUE _output_format) {
- AVFormatContext *format_context;
- AVOutputFormat *output_format;
-
- Data_Get_Struct(self, AVFormatContext, format_context);
- Data_Get_Struct(_output_format, AVOutputFormat, output_format);
-
- format_context->oformat = output_format;
-
- return self;
- }
- C
-
- ##
# :method: read_frame
builder.c <<-C
@@ -362,6 +375,9 @@ class FFMPEG::FormatContext
builder.reader :timestamp, 'int64_t'
end
+ attr_reader :format_parameters
+ attr_accessor :sync_pts
+
##
# +file+ accepts a file name or an IO for output
#
@@ -373,19 +389,21 @@ def initialize(file, output = false)
@sync_pts = 0
@video_stream = nil
@stream_info = nil
+ @format_parameters = FFMPEG::FormatParameters.new
+
unless output then
raise NotImplementedError, 'input from IO not supported' unless
String === file
- open_input_file file, nil, 0, nil
+ open_input_file file, nil, 0, @format_parameters
stream_info
else
@stream_info = true
output_format = FFMPEG::OutputFormat.guess_format nil, file, nil
- self.oformat = output_format
+ self.output_format = output_format
#self.filename = file # HACK av_strlcpy
file = "pipe:#{file.fileno}" if IO === file
@@ -394,6 +412,22 @@ def initialize(file, output = false)
end
end
+ ##
+ # Is there an audio stream?
+
+ def audio?
+ !!audio_stream
+ end
+
+ ##
+ # The first audio stream
+
+ def audio_stream
+ @audio_stream ||= streams.find do |stream|
+ stream.codec_context.codec_type == :AUDIO
+ end
+ end
+
def inspect
"#<%s:0x%x @input=%p @stream_info=%p @sync_pts=%d>" % [
self.class, object_id,
@@ -456,8 +490,7 @@ def output(packet, output_context, output_stream, input_stream)
len = packet.size
while len > 0 or
- (packet.nil? and
- input_stream.next_pts != input_stream.pts)
+ (packet.nil? and input_stream.next_pts != input_stream.pts) do
input_stream.pts = input_stream.next_pts
@@ -615,41 +648,56 @@ def prepare_transcoding(stream_map)
end
# output only
- def new_output_video_stream(codec_name=nil, options={})
+ def output_stream(codec_type, codec_name = nil, options={})
stream = new_output_stream
- stream.context_defaults FFMPEG::Codec::VIDEO
+ stream.context_defaults codec_type
+
+ codec_id = output_format.guess_codec codec_name, filename, nil, codec_type
- codec_id = output_format.guess_codec(codec_name, filename, nil,
- FFMPEG::Codec::VIDEO)
raise FFMPEG::Error, "unable to get codec #{codec_name}" unless codec_id
codec = FFMPEG::Codec.for_encoder codec_id
encoder = stream.codec_context
encoder.defaults
- (options.keys & [:bit_rate, :width, :height]).each do |key|
+ if output_format.flags & FFMPEG::FormatParameters::GLOBALHEADER ==
+ FFMPEG::FormatParameters::GLOBALHEADER then
+ encoder.flags |= FFMPEG::Codec::Flag::GLOBAL_HEADER
+ end
+
+ required = case codec_type
+ when FFMPEG::Codec::VIDEO then
+ [:bit_rate, :width, :height]
+ when FFMPEG::Codec::AUDIO then
+ [:bit_rate]
+ else raise NotImplementedError,
+ "codec type #{codec_type} not supported"
+ end
+
+ (options.keys & required).each do |key|
method = "#{key}=".to_sym
- value = options.delete key
- raise ArgumentError, "required option #{key} not set" if value.nil?
- stream.send method, value if stream.respond_to? method
- encoder.send method, value if encoder.respond_to? method
+ raise ArgumentError, "required option #{key} not set" unless
+ options.key? key
+ stream.send method, options[key] if stream.respond_to? method
+ encoder.send method, options[key] if encoder.respond_to? method
+ end
+
+ case codec_type
+ when FFMPEG::Codec::VIDEO then
+ encoder.pix_fmt = options[:pixel_format] || codec.pixel_formats[0]
+ encoder.fps = options[:fps] || FFMPEG.Rational(25,1)
+ when FFMPEG::Codec::AUDIO then
+ sample_rate = options[:sample_rate] || 44100
+ encoder.sample_rate = sample_rate
+ encoder.fps = FFMPEG.Rational 1, sample_rate
end
- encoder.pix_fmt = options.delete(:pixel_format) || codec.pixel_formats[0]
- encoder.fps = options.delete(:fps) || FFMPEG.Rational(25,1)
encoder.bit_rate_tolerance =
- options.delete(:bit_rate_tolerance) ||
- encoder.bit_rate * 10 / 100
+ options[:bit_rate_tolerance] || encoder.bit_rate * 10 / 100
encoder.codec_id = codec_id
encoder.open codec
- options.keys.each do |key|
- method = "#{key}=".to_sym
- stream.send method, options[key] if stream.respond_to?(method)
- encoder.send method, options[key] if encoder.respond_to?(method)
- end
-
stream
end
@@ -796,10 +844,16 @@ def transcode(wrapper, video, audio, io)
output_context.write_trailer
end
+ ##
+ # Is there a video stream?
+
def video?
!!video_stream
end
+ ##
+ # The first video stream
+
def video_stream
@video_stream ||= streams.find do |stream|
stream.codec_context.codec_type == :VIDEO
View
@@ -83,9 +83,9 @@ class FFMPEG::Packet
av_init_packet(packet);
packet->data = NULL;
packet->size = 0;
- packet->pts = AV_NOPTS_VALUE;
- packet->dts = AV_NOPTS_VALUE;
- packet->pos = -1;
+ packet->pts = AV_NOPTS_VALUE;
+ packet->dts = AV_NOPTS_VALUE;
+ packet->pos = -1;
return self;
}
@@ -111,5 +111,9 @@ def initialize
clean
end
+ def inspect
+ '#<%s size: %d>' % [self.class.name, size]
+ end
+
end
View
@@ -3,23 +3,27 @@
file = File.expand_path '../../test/Thumbs Up!.3gp', __FILE__
input = FFMPEG::FormatContext.new file
-input_video_steam = input.video_stream
flv = FFMPEG::FormatContext.new 'Thumbs Up!.flv', true
#mp4 = FFMPEG::FormatContext.new 'Thumbs Up!.mp4', true
-flv_stream = flv.new_output_video_stream('flv', :bit_rate => 1_000_000,
- :width => 300, :height => 200,
- :fps => FFMPEG.Rational(25, 1))
+flv_stream = flv.output_stream(FFMPEG::Codec::VIDEO, 'flv',
+ :bit_rate => 1_000_000,
+ :width => 300, :height => 200,
+ :fps => FFMPEG.Rational(25, 1))
+mp3_stream = flv.output_stream(FFMPEG::Codec::AUDIO, 'mp3',
+ #:width => 300, :height => 200,
+ :bit_rate => 128 * 1024)
#mp4_stream = mp4.new_output_video_stream('mpeg4', :bit_rate => 2_000_000,
# :width => 640, :height => 480,
# :gop_size => 12,
# :fps => FFMPEG.Rational(25,1))
input.transcode_map do |stream_map|
- stream_map.add input_video_steam, flv_stream
- #stream_map.add input_video_steam, mp4_stream
+ stream_map.add input.video_stream, flv_stream
+ stream_map.add input.audio_stream, mp3_stream
+ #stream_map.add input.video_stream, mp4_stream
end
# input.transcode 'mp4', 'mpeg4', 'mp3', "out.mp4"

0 comments on commit b456ea3

Please sign in to comment.