UAV-Pilot-SDL

 view release on metacpan or  search on metacpan

lib/UAV/Pilot/SDL/Video.pm  view on Meta::CPAN

    },
);
has '_bg_rect' => (
    is     => 'ro',
    isa    => 'SDL::Rect',
    writer => '_set_bg_rect',
);
has '_bg_color' => (
    is  => 'rw',
);
has 'video_overlays' => (
    is      => 'ro',
    isa     => 'ArrayRef[UAV::Pilot::SDL::VideoOverlay]',
    default => sub {[]},
    traits  => [ 'Array' ],
    handles => {
        _add_video_overlay => 'push',
    },
);

with 'UAV::Pilot::SDL::WindowEventHandler';


sub BUILDARGS
{
    my ($class, $args) = @_;
    $$args{width}     = $class->SDL_WIDTH;
    $$args{height}    = $class->SDL_HEIGHT;
    return $args;
}

sub add_to_window
{
    my ($self, $window, $location) = @_;
    $location //= $window->TOP;
    $window->add_child_with_yuv_overlay( $self,
        $self->SDL_OVERLAY_FLAG, $location );

    my @bg_color_parts = @{ $self->BG_COLOR };
    my $sdl = $window->sdl;
    my $bg_color = SDL::Video::map_RGB( $sdl->format, @bg_color_parts );
    $self->_bg_color( $bg_color );

    return 1;
}

sub update_window_rect
{
    # Do nothing, since YUV overlay updates the area for us
    return 1;
}


sub process_raw_frame
{
    my ($self, $width, $height, $decoder) = @_;

    if( ($width != $self->width) || ($height != $self->height) ) {
        # TODO Ignore until we have a way of informing 

lib/UAV/Pilot/SDL/Video.pm  view on Meta::CPAN

    $self->_add_frames_processed( 1 );
    return 1;
}

sub draw
{
    my ($self, $window) = @_;
    my $last_vid_frame = $self->_last_vid_frame;
    return 1 unless defined $last_vid_frame;

    my $bg_rect     = $window->yuv_overlay_rect;
    my $sdl_overlay = $window->yuv_overlay;
    SDL::Video::fill_rect(
        $window->sdl,
        $bg_rect,
        $self->_bg_color,
    );

    $self->_draw_last_video_frame(
        $sdl_overlay,
        $bg_rect,
        $last_vid_frame->get_last_frame_c_obj,
    );

    my @overlays = @{ $self->video_overlays };
    if( @overlays ) {
        foreach my $overlay (@overlays) {
            $overlay->process_video_overlay( $window );
        }
        
        SDL::Video::update_rects( $window->sdl, $bg_rect );
    }

    $self->_logger->info( 'VIDEO_FRAME_TIMER,DISPLAY,'
        . $self->frames_processed
        . ',' . join( ',', Time::HiRes::gettimeofday ) );

    return 1;
}

sub register_video_overlay
{
    my ($self, $overlay, $window) = @_;
    $overlay->init_video_overlay( $self, $window );
    $self->_add_video_overlay( $overlay );
    return 1;
}


sub _set_width_height
{
    my ($self, $width, $height) = @_;
    # TODO inform UAV::Pilot::SDL::Window of size change
    my $sdl         = $self->sdl_app;
    $sdl->resize( $width, $height );
    my $bg_rect     = SDL::Rect->new( 0, 0, $width, $height );
    my $sdl_overlay = SDL::Overlay->new( $width, $height, $self->SDL_OVERLAY_FLAG, $sdl );

    $self->_set_bg_rect( $bg_rect );
    $self->_set_sdl_overlay( $sdl_overlay );
    $self->_set_width( $width );
    $self->_set_height( $height );

    return 1;
}


no Moose;
__PACKAGE__->meta->make_immutable;
1;

lib/UAV/Pilot/SDL/Video.pm  view on Meta::CPAN

    
    $events->register( $display );

=head1 DESCRIPTION

Process raw video frames and displays them to an SDL surface.  This does the roles
C<UAV::Pilot::Video::RawHandler> and C<UAV::Pilot::EventHandler>.

=head1 METHODS

=head1 register_video_overlay

    register_video_overlay( $overlay )

Adds an object that does the C<UAV::Pilot::SDL::VideoOverlay> role.  This allows an 
object to draw things on top of the video, like telemetry information.

Not to be confused with C<SDL::Overlay>.

=cut

lib/UAV/Pilot/SDL/Video.xs  view on Meta::CPAN


#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <SDL/SDL.h>


MODULE = UAV::Pilot::SDL::Video    PACKAGE = UAV::Pilot::SDL::Video


void
_draw_last_video_frame( self, overlay, dstrect, frame_sv)
        SV* self
        SDL_Overlay* overlay
        SDL_Rect* dstrect
        SV* frame_sv
    PPCODE:
        AVFrame* frame = (AVFrame*) SvIV( frame_sv );
        AVPicture pict;
        struct SwsContext * sws_context = sws_getContext(
            dstrect->w,
            dstrect->h,
            UAV_PIX_FMT,
            dstrect->w,

lib/UAV/Pilot/SDL/Video.xs  view on Meta::CPAN

            NULL,
            NULL
        );

        if( sws_context == NULL ) {
            warn( "Could not get SWS context\n" );
            exit( 1 );
        }


        SDL_LockYUVOverlay( overlay );

        // Data comes from YUV420P source; U and V arrays swapped
        pict.data[0] = overlay->pixels[0];
        pict.data[1] = overlay->pixels[2];
        pict.data[2] = overlay->pixels[1];
        pict.linesize[0] = overlay->pitches[0];
        pict.linesize[1] = overlay->pitches[2];
        pict.linesize[2] = overlay->pitches[1];

        sws_scale( sws_context, (const uint8_t * const *) frame->data,
            frame->linesize, 0, dstrect->h, pict.data, pict.linesize );

        SDL_UnlockYUVOverlay( overlay );
        SDL_DisplayYUVOverlay( overlay, dstrect );

        sws_freeContext( sws_context );

lib/UAV/Pilot/SDL/VideoOverlay.pm  view on Meta::CPAN

# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
package UAV::Pilot::SDL::VideoOverlay;
use v5.14;
use Moose::Role;

requires 'process_video_overlay';

has 'video_overlay' => (
    is     => 'ro',
    isa    => 'Maybe[UAV::Pilot::SDL::Video]',
    writer => '_set_video_overlay',
);


sub init_video_overlay
{
    my ($self, $video) = @_;
    $self->_set_video_overlay( $video );
    return 1;
}


1;
__END__


=head1 NAME

  UAV::Pilot::SDL::VideoOverlay

=head1 DESCRIPTION

A role for objects to draw on top of a video.  Requires a
C<process_video_overlay()> method, which will be passed the C<UAV::Pilot::SDL::Window> object that the video is drawing to.

Where C<$video> is an C<UAV::Pilot::SDL::Video> object, you can set an 
C<$overlay> object with:

    $video->register_video_overlay( $overlay );

B<NOTE>: This is still experimental.  Lines tend to flicker and show up as 
black.  This is probably due to the SDL YUV hardware overlay.

=cut

lib/UAV/Pilot/SDL/VideoOverlay/Reticle.pm  view on Meta::CPAN

use constant RETICLE_HALF_SIZE_PERCENT => 0.1; # Takes up x percent of screen size

with 'UAV::Pilot::SDL::VideoOverlay';

has 'reticle_color' => (
    is     => 'ro',
    writer => '_set_reticle_color',
);


after 'init_video_overlay' => sub {
    my ($self, $video, $window) = @_;
    my $sdl = $window->sdl;
    my @color_parts = @{ $self->RETICLE_COLOR };
    my $reticle_color = SDL::Video::map_RGB( $sdl->format, @color_parts );
    $self->_set_reticle_color( $reticle_color );

    return 1;
};


sub process_video_overlay
{
    my ($self, $window) = @_;
    my $sdl               = $window->sdl;
    my $reticle_color     = $self->reticle_color;
    my $half_size_percent = $self->RETICLE_HALF_SIZE_PERCENT;
    # TODO this needs to be based on the rect that the Video is being drawn on
    my $w                 = $sdl->w;
    my $h                 = $sdl->h;
    my $center_x          = int( $w / 2 );
    my $center_y          = int( $h / 2 );

lib/UAV/Pilot/SDL/Window.pm  view on Meta::CPAN

has 'children' => (
    traits  => ['Array'],
    is      => 'ro',
    isa     => 'ArrayRef[HashRef[Item]]',
    default => sub {[]},
    handles => {
        '_add_child'       => 'push',
        '_has_no_children' => 'is_empty',
    },
);
has 'yuv_overlay' => (
    is     => 'ro',
    isa    => 'Maybe[SDL::Overlay]',
    writer => '_set_yuv_overlay',
);
has 'yuv_overlay_rect' => (
    is     => 'ro',
    isa    => 'Maybe[SDL::Rect]',
    writer => '_set_yuv_overlay_rect',
);
has 'width' => (
    is      => 'ro',
    isa     => 'Int',
    default => 0,
    writer  => '_set_width',
);
has 'height' => (
    is      => 'ro',
    isa     => 'Int',

lib/UAV/Pilot/SDL/Window.pm  view on Meta::CPAN

    $self->_resize( $new_width, $new_height );
    $self->_add_child({
        origin_x => $x,
        origin_y => $y,
        drawer   => $child,
    });

    return 1;
}

sub add_child_with_yuv_overlay
{
    my ($self, $child, $overlay_flag, $float) = @_;
    $float //= $self->TOP;

    my $width  = $child->width;
    my $height = $child->height;
    my ($x, $y, $new_width, $new_height) = $self->_calc_new_child(
        $child, $float );

    my $sdl = $self->sdl;
    my $overlay = SDL::Overlay->new( $width, $height, $overlay_flag, $sdl );
    my $overlay_rect = SDL::Rect->new( $x, $y, $width, $height );

    $self->_set_yuv_overlay( $overlay );
    $self->_set_yuv_overlay_rect( $overlay_rect );

    $self->_resize( $new_width, $new_height );
    $self->_add_child({
        origin_x => $x,
        origin_y => $y,
        drawer   => $child,
    });
    return 1;
}

lib/UAV/Pilot/SDL/Window.pm  view on Meta::CPAN

=head1 METHODS

=head2 add_child

    add_child( $handler, $float ).

Pass a child that does the C<UAV::Pilot::SDL::WindowEventHandler> role.  
Float should be C<<$window->TOP>> or C<<$window->BOTTOM>> for the location to 
draw this child.  The window will be expanded to fit the child's width/height.

=head2 add_child_with_yuv_overlay

    add_child_with_yuv_overlay( $handle, $overlay_flag, $float )

Pass a child that does the C<UAV::Pilot::SDL::WindowEventHandler> role.  The 
C<$overlay_flag> will be the flag passed to C<SDL::Overlay> (see that module's 
docs for details).  The C<$float> param is the same as C<add_child()>.

=head2 sdl

Returns the C<SDLx::App> object for the given SDL window.

=head2 yuv_overlay

If a child was added with C<add_child_with_yuv_overlay()>, returns the 
C<SDL::Overlay> object.

=head2 yuv_overlay_rect

If a child was added with C<add_child_with_yuv_overlay()>, returns an 
C<SDL::Rect> object that covers the overlay area.

=head1 DRAWING METHODS

The should only be used by widgets when their C<draw()> method is called.

All C<$x, $y> coordinates are relative to the widgets's drawing area.

=head2 clear_screen

Blanks the area that the current widget is being drawn in.



( run in 0.669 second using v1.01-cache-2.11-cpan-3b35f9de6a3 )