Class: Libav::Stream::Video
- Inherits:
-
Object
- Object
- Libav::Stream::Video
- Includes:
- Libav::Stream
- Defined in:
- lib/libav/stream.rb
Instance Attribute Summary collapse
-
#afs ⇒ Object
readonly
Returns the value of attribute afs.
-
#height ⇒ Object
Returns the value of attribute height.
-
#pixel_format ⇒ Object
Returns the value of attribute pixel_format.
-
#reader ⇒ Object
readonly
Returns the value of attribute reader.
-
#width ⇒ Object
Returns the value of attribute width.
Attributes included from Libav::Stream
#av_codec_ctx, #av_stream, #buffer
Instance Method Summary collapse
-
#buffer=(v) ⇒ Object
Set the buffer size.
-
#decode_frame(packet) ⇒ Object
Called by Libav::Reader.each_frame to decode each frame.
- #fps ⇒ Object
-
#initialize(p = {}) ⇒ Video
constructor
A new instance of Video.
-
#release_all_frames ⇒ Object
This method will make the stream release all references to buffered frames.
- #release_frame(frame) ⇒ Object
- #rewind(count = nil) ⇒ Object
-
#scaling? ⇒ Boolean
Check to see if this frame is being scaled.
Methods included from Libav::Stream
#discard, #discard=, #each_frame, #format_afs, #index, #next_frame, #seek, #skip_frames, #type
Constructor Details
#initialize(p = {}) ⇒ Video
Returns a new instance of Video.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/libav/stream.rb', line 228 def initialize(p={}) super(p) # Handle frame width and height and setup any scaling necessary @width = p[:widht] || @av_codec_ctx[:width] @height = p[:height] || @av_codec_ctx[:height] @pixel_format = p[:pixel_format] || @av_codec_ctx[:pix_fmt] # Our stream index info @afs = p[:afs] @update_afs = @afs.nil? == false # Our array and queues for raw frames and scaled frames @raw_frames = [] @raw_queue = Queue.new @scaled_frames = [] @scaled_queue = Queue.new # Number of frames to buffer (default is disabled, 0) @buffer = 0 # When this is set to true when all raw and scaled frames have been set up # by setup(). @decode_ready = false # Pointer used to denote that decode frame was successful @frame_finished = FFI::MemoryPointer.new :int # Elaborate schemes to capture an accurate pts value. When the buffer for # the frame is allocated, we pull the dts from the last packet processed # (set in decode_frame()), and set it in the opaque field of the frame. # # Since we may be running on a 32-bit platform, we can't just shove the # 64-bit dts in the :opaque pointer, so we have to alloc some space for the # address. Instead of allocating and freeing repeatedly, we're going to # alloc it once now and reuse it for each decoded frame. @last_dts = nil @last_pos = nil @opaque = FFI::MemoryPointer.new :uint64, 2 @av_codec_ctx[:get_buffer] = \ FFI::Function.new(:int, [AVCodecContext.ptr, AVFrame.ptr]) do |ctx,frame| # Use the default method to get the buffer ret = avcodec_default_get_buffer(ctx, frame) # Update the :opaque field point at a copy of the last pts we've seen. @opaque.put_int64(0, @last_dts) @opaque.put_uint64(8, @last_pos) frame[:opaque] = @opaque ret end # Initialize our frame number oafset, and our pts oafset. These two are # modified by seek(), and used by decode_frame(). @frame_oafset = 0 @pts_oafset = 0 end |
Instance Attribute Details
#afs ⇒ Object (readonly)
Returns the value of attribute afs.
226 227 228 |
# File 'lib/libav/stream.rb', line 226 def afs @afs end |
#height ⇒ Object
Returns the value of attribute height.
226 227 228 |
# File 'lib/libav/stream.rb', line 226 def height @height end |
#pixel_format ⇒ Object
Returns the value of attribute pixel_format.
226 227 228 |
# File 'lib/libav/stream.rb', line 226 def pixel_format @pixel_format end |
#reader ⇒ Object (readonly)
Returns the value of attribute reader.
226 227 228 |
# File 'lib/libav/stream.rb', line 226 def reader @reader end |
#width ⇒ Object
Returns the value of attribute width.
226 227 228 |
# File 'lib/libav/stream.rb', line 226 def width @width end |
Instance Method Details
#buffer=(v) ⇒ Object
Set the buffer size
318 319 320 321 322 |
# File 'lib/libav/stream.rb', line 318 def buffer=(v) return if v == @buffer @buffer = v teardown end |
#decode_frame(packet) ⇒ Object
Called by Libav::Reader.each_frame to decode each frame
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
# File 'lib/libav/stream.rb', line 332 def decode_frame(packet) setup unless @decode_ready # Save off our dts and pos for the buffer allocation callback we declared # in #initialize @last_dts = packet[:dts] @last_pos = packet[:pos] # Grab our raw frame off the raw frames queue. This will block if the # caller is still using all the previous frames. raw_frame = @raw_queue.shift # Let the reader know we're stomping on this frame @reader.frame_dirty(raw_frame) # Call the decode function on our packet avcodec_get_frame_defaults(raw_frame.av_frame) rc = avcodec_decode_video2(@av_codec_ctx, raw_frame.av_frame, @frame_finished, packet) # Now, if we didn't get a frame, for one reason or another, let's throw the # raw frame back on our queue. if rc < 0 or @frame_finished.read_int == 0 @raw_queue.push raw_frame return nil end raw_frame.number = @av_codec_ctx[:frame_number].to_i + @frame_oafset raw_frame.pts = raw_frame.av_frame[:opaque].get_int64(0) + @pts_oafset raw_frame.pos = raw_frame.av_frame[:opaque].get_uint64(8) # AFS Data is broken down as follows: # [ [frame number, pts, pos, true], # entry for first key frame # [frame number, pts, pos, true], # entry for second key frame # [frame number, pts, pos, true], # entry for N-th key frame # [frame number, pts, pos, false], # optional, last non-key frame # ] if @update_afs and (@afs.empty? or raw_frame.number > @afs.last[0]) @afs.pop unless @afs.empty? or @afs.last[-1] == true @afs << [ raw_frame.number, raw_frame.pts, raw_frame.pos, raw_frame.key_frame? ] end # If we're scaling, or not buffering, throw the raw frame back on the # queue; it's the only one we have @raw_queue.push raw_frame if @swscale_ctx or @buffer == 0 # If we're not scaling at this point, we need to return the raw frame to # the caller. This is the non-buffering, non-scaling return point. return raw_frame unless @swscale_ctx # Let's grab a scaled frame from our queue scaled_frame = @scaled_queue.shift # Let the reader know we're stomping on this frame @reader.frame_dirty(scaled_frame) # scale the frame raw_frame.scale(:scale_ctx => @swscale_ctx, :output_frame => scaled_frame) # Throw the scaled frame back on the queue if we're not buffering @scaled_queue.push scaled_frame if @buffer == 0 scaled_frame end |
#fps ⇒ Object
289 290 291 292 293 294 |
# File 'lib/libav/stream.rb', line 289 def fps fps = @av_stream[:r_frame_rate].to_f # Some codecs don't set frame rate, so we'll use 1/timebase fps = 1/@av_stream[:time_base].to_f if fps.nan? fps end |
#release_all_frames ⇒ Object
This method will make the stream release all references to buffered frames. The buffers will be recreated the next time #decode_frame is called.
410 411 412 |
# File 'lib/libav/stream.rb', line 410 def release_all_frames teardown end |
#release_frame(frame) ⇒ Object
399 400 401 402 |
# File 'lib/libav/stream.rb', line 399 def release_frame(frame) @scaled_queue.push frame if @scaled_frames.include? frame @raw_queue.push frame if @raw_frames.include? frame end |
#rewind(count = nil) ⇒ Object
404 405 406 |
# File 'lib/libav/stream.rb', line 404 def rewind(count=nil) @reader.rewind(count, :stream => self) end |
#scaling? ⇒ Boolean
Check to see if this frame is being scaled
325 326 327 328 329 |
# File 'lib/libav/stream.rb', line 325 def scaling? @av_codec_ctx[:width] != @width or @av_codec_ctx[:height] != @height or @av_codec_ctx[:pix_fmt] != @pixel_format end |