File Coverage

blib/lib/Video/Generator.pm
Criterion Covered Total %
statement 60 80 75.0
branch 4 20 20.0
condition n/a
subroutine 13 14 92.8
pod 2 2 100.0
total 79 116 68.1


line stmt bran cond sub pod time code
1             package Video::Generator;
2              
3 3     3   151276 use strict;
  3         23  
  3         85  
4 3     3   17 use warnings;
  3         6  
  3         91  
5              
6 3     3   1386 use Class::Utils qw(set_params);
  3         28384  
  3         1708  
7 3     3   225 use Error::Pure qw(err);
  3         7  
  3         102  
8 3     3   1385 use FFmpeg::Command;
  3         141160  
  3         25  
9 3     3   177 use File::Path qw(rmtree);
  3         8  
  3         221  
10 3     3   1390 use File::Spec::Functions qw(catfile);
  3         2916  
  3         198  
11 3     3   2311 use File::Temp qw(tempdir);
  3         37573  
  3         178  
12 3     3   1388 use Image::Random;
  3         172977  
  3         111  
13 3     3   29 use Readonly;
  3         6  
  3         149  
14 3     3   1412 use Video::Delay::Const;
  3         699  
  3         86  
15 3     3   1355 use Video::Pattern;
  3         5397  
  3         2001  
16              
17             # Constants.
18             Readonly::Scalar our $DEFAULT_DURATION => 10000;
19             Readonly::Scalar our $DEFAULT_VIDEO_HEIGHT => 1080;
20             Readonly::Scalar our $DEFAULT_VIDEO_WIDTH => 1920;
21             Readonly::Scalar our $SPACE => q{ };
22              
23             our $VERSION = 0.10;
24              
25             # Constructor.
26             sub new {
27 9     9 1 19932 my ($class, @params) = @_;
28              
29             # Create object.
30 9         24 my $self = bless {}, $class;
31              
32             # Delay generator.
33 9         30 $self->{'delay_generator'} = undef;
34              
35             # Duration.
36 9         16 $self->{'duration'} = $DEFAULT_DURATION;
37              
38             # Frames per second.
39 9         18 $self->{'fps'} = 60;
40              
41             # FFmpeg pixel format.
42 9         13 $self->{'ffmpeg_pixel_format'} = undef;
43              
44             # FFmpeg video codec.
45 9         17 $self->{'ffmpeg_video_codec'} = undef;
46              
47             # Image generator.
48 9         15 $self->{'image_generator'} = undef;
49              
50             # Image type.
51 9         16 $self->{'image_type'} = 'bmp';
52              
53             # Temporary dir.
54 9         24 $self->{'temp_dir'} = undef;
55              
56             # Verbose mode.
57 9         17 $self->{'verbose'} = 0;
58              
59             # Video pattern generator.
60 9         16 $self->{'video_pattern'} = undef;
61              
62             # Sizes.
63 9         15 $self->{'height'} = $DEFAULT_VIDEO_HEIGHT;
64 9         18 $self->{'width'} = $DEFAULT_VIDEO_WIDTH;
65              
66             # Process params.
67 9         33 set_params($self, @params);
68              
69             # Temporary directory.
70 7 50       92 if (! defined $self->{'temp_dir'}) {
71 7         25 $self->{'temp_dir'} = tempdir();
72             }
73              
74             # Image generator.
75 7 50       2401 if (! defined $self->{'image_generator'}) {
76             $self->{'image_generator'} = Image::Random->new(
77             'height' => $self->{'height'},
78             'type' => $self->{'image_type'},
79 7         38 'width' => $self->{'width'},
80             );
81             }
82              
83             # Delay generator.
84 6 50       13554 if (! defined $self->{'delay_generator'}) {
85 6         28 $self->{'delay_generator'} = Video::Delay::Const->new(
86             'const' => 1000,
87             );
88             }
89              
90             # Video pattern generator.
91 6 50       146 if (! defined $self->{'video_pattern'}) {
92             $self->{'video_pattern'} = Video::Pattern->new(
93             'delay_generator' => $self->{'delay_generator'},
94             'duration' => $self->{'duration'},
95             'fps' => $self->{'fps'},
96 6         28 'image_generator' => $self->{'image_generator'},
97             );
98             }
99              
100             # Object.
101 1         101 return $self;
102             }
103              
104             # Create random video.
105             sub create {
106 0     0 1   my ($self, $out_path) = @_;
107              
108             # Create images.
109 0           $self->{'video_pattern'}->create($self->{'temp_dir'});
110 0 0         if ($self->{'verbose'}) {
111 0           print "Video pattern generator created images for video in ".
112             "temporary directory.\n";
113             }
114              
115             # Create video.
116 0           my $ffmpeg = FFmpeg::Command->new;
117             my $images_path = catfile($self->{'temp_dir'},
118 0           '%03d.'.$self->{'image_type'});
119             my @command_options = ('-loglevel', 'error', '-r', $self->{'fps'},
120             '-i', $images_path,
121             $self->{'ffmpeg_video_codec'}
122             ? ('-c:v', $self->{'ffmpeg_video_codec'})
123             : (),
124             $self->{'ffmpeg_pixel_format'}
125 0 0         ? ('-pix_fmt', $self->{'ffmpeg_pixel_format'})
    0          
126             :(),
127             '-pix_fmt', 'yuv420p',
128             $out_path);
129 0           $ffmpeg->options(@command_options);
130 0           $ffmpeg->exec;
131 0 0         if ($ffmpeg->stderr) {
132 0           my @stderr = split m/\n/ms, $ffmpeg->stderr;
133 0           my $command = join $SPACE, @command_options;
134             err "Error with command 'ffmpeg $command'.",
135 0           map { ('STDERR', $_) } @stderr;
  0            
136             }
137 0 0         if ($self->{'verbose'}) {
138 0           print "Created video file.\n";
139             }
140              
141             # Remove temporary directory.
142 0           rmtree $self->{'temp_dir'};
143 0 0         if ($self->{'verbose'}) {
144 0           print "Removed temporary directory.\n";
145             }
146              
147 0           return;
148             }
149              
150             1;
151              
152             __END__