The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

VideoLAN::LibVLC - Wrapper for libvlc.so

VERSION

version 0.06

SYNOPSIS

use VideoLAN::LibVLC::MediaPlayer;
use AnyEvent; # or whatever your favorite event loop is
my $exit_cv= AE::cv;
# Tell event loop to call callback_dispatch any time callback_fh is readable
my $vlc= VideoLAN::LibVLC->new;
my $listen_vlc= AE::io $vlc->callback_fh, 0, sub { $vlc->callback_dispatch };

my $player= $vlc->new_media_player("funny_cats.avi");
$player->set_video_callbacks(
  # callback when player needs new picture buffer
  lock => sub ($player, $event) {
    # Allocate automatically using queue_new_picture
    $player->queue_new_picture(id => ++$next_pic_id)
      while $player->queued_picture_count < 8
  },
  # callback when it is time to display a filled picture buffer
  display => sub ($player, $event) {
    do_stuff( $event->{picture} );  # do something with the picture
    $player->queue_picture($event->{picture});  # recycle the buffer
  },
);
$player->play; # start VLC thread that decodes and generates callbacks
exit $exit_cv->recv; # give control to event loop

DESCRIPTION

This module wraps LibVLC. The primary reason to use LibVLC instead of running VLC as a child process is to get programmatic access to the video frames coming from the decoder in real time. If you just want to iterate the frames of a video for some kind of non-realtime analysis, you probably want LibAV instead. LibVLC is primarily used to implement video players with alternate rendering, like sending the video frames to OpenGL textures, websockets, aalib, or other creative uses for which VLC doesn't have an output plugin.

LibVLC already has a very nice object-ish (yet still function-based) API, so this package wraps each group of functions into a perl object in the logical manner. One difficulty, however, is that LibVLC delivers audio and video via callbacks, and uses multiple threads for playback, which forces callbacks to deal with multithreading issues. Perl needs all callbacks to run from the main thread, so this module solves that by converting callbacks into events, and streaming them through a pipe. You can then fit this into an event loop of your choice by watching the read-state of the pipe and calling the dispatcher. You pretty much always need to integrate this into your event loop since even logging output is handled via callbacks. However, it only needs done for the top level VideoLAN::LibVLC instance, not for each player object. See "callback_dispatch" for details.

CONSTANTS

This module can export constants used by LibVLC, however I renamed them a bit because libvlc uses a mix of uppercase/lowercase/camel-case that is distracting and confusing when used as perl const-subs, the LIBVLC_ prefix is annoying for perl scripts, and some constants only differ by case.

The renaming rules are:

  • Remove any "LIBVLC_" or "libvlc_" prefix

  • If the constant does not begin with the same word as the enum it belongs to, add the enum's name to the beginning of the constant

  • Uppercase everything

for example:

LIBVLC_ERROR      =>   LOG_LEVEL_ERROR
libvlc_Error      =>   STATE_ERROR
libvlc_meta_Album =>   META_ALBUM

Each of LibVLC's enums can be exported individually:

use VideoLAN::LibVLC qw( :log_level_t :media_parse_flag_t :media_parsed_status_t
 :media_slave_type_t :media_type_t :position_t :state_t :track_type_t
 :video_orient_t :video_projection_t );

Or get all of them with :constants.

However, be aware that the constants change significantly across libvlc versions, but this module always exports all of them. Accessing a constant not supported by your version of libvlc will throw an exception. (I figured it would be better to allow the exceptions at runtime than for programs to break at compile time due to the host's version of libvlc.)

ATTRIBUTES

libvlc_version

Version of LibVLC. This is a package attribute.

libvlc_changeset

Precise revision-control version of LibVLC. This is a package attribute.

libvlc_compiler

Compiler used to create LibVLC. This is a package attribute.

argv

A copy of the argv that you passed to the constructor. Read-only.

app_id

A java-style name identifying the application. Defaults to an empty string if you set app_version or app_icon.

app_version

The version of your application. Defaults to empty string if you assign an app_id or app_icon.

app_icon

The name of the icon for your application. Defaults to empty string if you assign an app_id or app_version.

user_agent_name

A human-facing description of your application as a user agent for web requests.

user_agent_http

A HTTP UserAgent string for your application.

audio_filters

An arrayref of all audio filter modules built into LibVLC.

audio_filter_list

List accessor for audio_filters.

video_filters

An arrayref of all video filter modules built into LibVLC.

video_filter_list

List accessor for video_filters.

can_redirect_log

Whether or not this version of libvlc supports redirecting the log.

log

# get
my $current= $vlc->log

# set to logger object
$vlc->log( $log );
$vlc->log( $log, \%options );

# set to logging callback
$vlc->log( sub { my ($event)= @_; ... } );
$vlc->log( sub { my ($event)= @_; ... }, \%options );

# disable logging
$vlc->log(undef);

Set the logger object or logging callback or logging file handle for this LibVLC instance. It can be either a logger object like Log::Any, or a callback. The $event passed to the callback is a hashref containing message, level, and possibly other fields if requested by $options{fields}.

The optional second argument \%options can request more or less information about the log message. Available options are:

level  => one of LOG_LEVEL_DEBUG LOG_LEVEL_NOTICE LOG_LEVEL_WARNING LOG_LEVEL_ERROR
fields => arrayref set of [ "module", "file", "line", "name", "header", "objid" ]
          or '*' to select all of them.  Each selected field will appear in the
          log $event.

for example,

$vlc->log($log, { level => LOG_LEVEL_WARNING, fields => [qw( file line )] });

Note that logging can happen from other threads, so you won't see the messages until you call "callback_dispatch".

METHODS

new

my $vlc= VideoLAN::VLC->new( \@ARGV );
my $vlc= VideoLAN::VLC->new( %attributes );
my $vlc= VideoLAN::VLC->new( \%attributes );

Create a new instance of LibVLC (which directly corresponds to an initialization of libvlc via libvlc_new)

Note that libvlc suggests against passing command line arguments except for debugging, since they can differ by version and by platform.

The returned object is based on a hashref, and the libvlc pointer is magically attached.

new_media

my $media= $vlc->new_media( $path );
my $media= $vlc->new_media( $uri );
my $media= $vlc->new_media( $file_handle );
my $media= $vlc->new_media( %attributes );
my $media= $vlc->new_media( \%attributes );

This nice heavily-overloaded method helps you quickly open new media streams. VLC can open paths, URIs, or file handles, and if you only pass one argument to this method it attempts to decide which of those three you intended.

You can instead pass a hash or hashref, and then it just passes them along to the Media constructor.

new_media_player

my $player= $vlc->new_media_player();

Creates a new VideoLAN::LibVLC::MediaPlayer

callback_fh

The file handle of the read-end of the callback pipe. Watch the readable status of this file handle to know when to call "callback_dispatch". DO NOT READ OR WRITE IT FOR ANY REASON, lest ye incur the Wrath of the Segfault.

callback_dispatch

Read any pending callback messages from the pipe(s), and execute the callback. This method does not block (unless your callback does). You can wait for the file handle "callback_fh" to become readable to know when to call this method.

AnyEvent example:
my $vlc= VideoLAN::LibVLC->new;
my $watcher= AE::io $vlc->callback_fh, 0, sub { $vlc->callback_dispatch };  
IO::Async example:
my $vlc= VideoLAN::LibVLC->new;
$loop->add( IO::Async::Handle->new(
  handle => $vlc->callback_fh,
  on_read_ready => sub { $vlc->callback_dispatch },
));
Manual event loop example:
my $vlc= VideoLAN::LibVLC->new;
while (1) {
  if (IO::Select->new($vlc->callback_fh)->can_read) {
    $vlc->callback_dispatch;
  }
}

The "wire format" used to stream the callbacks is deliberately hidden within this module. It does not contain any user-servicable parts.

libvlc_video_set_callbacks

libvlc_video_set_callbacks($player, $lock_cb, $unlock_cb, $display_cb, $opaque);

This is part of the LibVLC API, but you should use "set_video_callbacks" in VideoLAN::LibVLC::MediaPlayer instead.

libvlc_video_set_format_callbacks

libvlc_video_set_format_callbacks($player, $format_cb, $cleanup_cb);

This is part of the LibVLC API, but you should use "set_video_callbacks" in VideoLAN::LibVLC::MediaPlayer instead.

AUTHOR

Michael Conrad <mike@nrdvana.net>

COPYRIGHT AND LICENSE

This software is copyright (c) 2023 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.