File Coverage

blib/lib/FFmpeg/Thumbnail.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package FFmpeg::Thumbnail;
2              
3 1     1   34259 use warnings;
  1         2  
  1         36  
4 1     1   6 use strict;
  1         2  
  1         34  
5 1     1   466 use Moose;
  0            
  0            
6              
7             use FFmpeg::Command;
8             use Capture::Tiny qw/ capture / ;
9             use Regexp::Common;
10             use Scalar::Util qw/looks_like_number/;
11              
12             =head1 NAME
13              
14             FFmpeg::Thumbnail - Create a thumbnail from a video
15              
16             =head1 VERSION
17              
18             Version 0.01
19              
20             =cut
21              
22             our $VERSION = '0.02';
23              
24             =head1 DESCRIPTION
25              
26             A wrapper for FFmpeg::Command specifically for creating video thumbnails. Grabs a frame at
27             a specific point in the video and stores it as an image using ffmpeg ( L<http://ffmpeg.org> ).
28              
29             Provides the ability to set specific output paramaters, such as file-type and file size, and use them
30             across multiple video files.
31              
32              
33             =head1 SYNOPSIS
34              
35             use FFmpeg::Thumbnail;
36              
37             # Create a thumbnail 20 seconds into the video.
38             my $foo = FFmpeg::Thumbnail->new( { video => '/my/video/file.flv' } );
39             my $offset = 20;
40             my $output_filname = "/my/output/image.png";
41             $foo->create_thumbnail( $offset, $output_filename );
42              
43              
44             # Create five evenly-spaced jpeg's
45             my $bar = FFmpeg::Thumbnail->new( { video => '/my/video/file.flv' } );
46             $bar->file_format( 'mjpeg');
47             my $filename( '/my/default/filename_' );
48             my $num_thumbs = 5;
49             for ( my $i=0; $i <= $bar->duration; $i+=$bar->duration / $num_thumbs ){
50             $bar->create_thumbnail( $i, $filename.$i."_.jpeg" );
51             }
52              
53              
54             # Create 640x480 thumbnails at 21 seconds for two separate videos
55             my $baz = FFmpeg::Thumbnail->new( { video => '/my/video/file.flv' } );
56             $baz->output_width( 640 );
57             $baz->output_height( 480 );
58             $baz->offset( 21 );
59             $baz->create_thumbnail( undef, '/my/first/thumbnail.png');
60              
61             $baz->video( '/my/video/second_file.flv' );
62             $baz->create_thumbnail( undef, '/my/second/thumbnail.png');
63              
64              
65             =head1 ATTRIBUTES
66              
67             =head2 video
68              
69             Complete path and filename for the source video. It can be changed after instantiantion if you wish
70             to use the same output settings for different videos.
71              
72             =cut
73              
74             has 'video' => (
75             is => 'rw',
76             isa => 'Str',
77             trigger => sub { my $self = shift; $self->_reset; },
78             );
79              
80             =head2 ffmpeg
81              
82             FFmpeg::Command object with handles to all of the FFmepg::Command methods. Automatically set
83             when the 'video' attribute is set. (Readonly)
84              
85             =cut
86              
87             has 'ffmpeg' => (
88             is => 'ro',
89             isa => 'FFmpeg::Command',
90             lazy => 1,
91             builder => '_build_ffmpeg',
92             clearer => 'clear_ffmpeg',
93             handles => {
94             undef => 'input_options',
95             undef => 'input_file',
96             output_options => 'output_options',
97             output_file => 'output_file',
98             options => 'options',
99             stdout => 'stdout',
100             stderr => 'stderr',
101             execute => 'execute',
102             },
103             );
104              
105             =head2 duration
106              
107             The length of the video, stored in seconds. It is automatically calculated and set from the 'ffmpeg'
108             attribue.
109             (Readonly)
110              
111             =cut
112              
113             has 'duration' => (
114             is => 'ro',
115             isa => 'Int',
116             lazy => 1,
117             predicate => 'has_ffmpeg',
118             builder => '_build_duration',
119             clearer => 'clear_duration',
120             );
121              
122              
123             =head2 filename
124              
125             Output filename. The filename extension, here, has no bearing on the actual output format.
126             That is set by the 'file_format' attribute, so it is possible to create a thumbnail named "thumbnail.jpg"
127             that actually has an 'image/png' MIME type. Defaults to "/tmp/thumbnail.png"
128              
129             =cut
130              
131             has 'filename' => (
132             is => 'rw',
133             isa => 'Str',
134             default => '/tmp/thumbnail.png',
135             );
136              
137             =head2 default_offset
138              
139             The time in the video (in seconds) at which to grab the thumbnail
140              
141             =cut
142              
143             has 'offset' => (
144             is => 'rw',
145             isa => 'Num',
146             default => 0,
147             );
148              
149             =head2 file_format
150              
151             Ffmpeg output file format, used by the '-f' argument. Defaults to 'image2' (png). 'mjpeg' (jpeg) is also known to work.
152              
153             =cut
154             has 'file_format' => (
155             is => 'rw',
156             isa => 'Str',
157             default => 'image2',
158             );
159              
160             =head2 output_width
161              
162             Width of the output thumnbail. Default output image size is 320x240.
163              
164             =cut
165              
166             has 'output_width' => (
167             is => 'rw',
168             isa => 'Int',
169             default => '320',
170             );
171              
172             =head2 output_width
173              
174             Height of the output thumbnail. Default output image size is 320x240.
175              
176             =cut
177              
178             has 'output_height' => (
179             is => 'rw',
180             isa => 'Int',
181             default => '240',
182             );
183              
184             =head2 hide_log_output
185              
186             Turns off ffmpeg's log output. You can still access this through the stdout() and
187             stderr() handles. Log output is suppressed by default ( ->hide_log_output == 1 ).
188              
189             =cut
190              
191             has 'hide_log_output' => (
192             is => 'rw',
193             isa => 'Int',
194             default => 1,
195             );
196              
197              
198             =head1 METHODS
199              
200             =head2 create_thumbnail
201              
202             Creats a thumbnail image using a specified offset and specified filename, or, if not specified, defaults. Will overwrite if a file already exists with that filename.
203              
204             Usage:
205              
206             # Create a thumbnail from $offset and store it at $output_filename:
207             $foo->create_thumbnail( $offset, $output_filename );
208              
209             # Create a thumbnail from $offset and store it at the default location:
210             $foo->create_thumbnail( $offset );
211              
212             # Create a thumbnail from the video's beginning and store it at $filename:
213             $foo->create_thumbnail( undef, $output_filename);
214              
215             # Create a thumbnail from the video's beginning and store it at the default location:
216             $foo->create_thumbnail();
217              
218             =cut
219              
220             sub create_thumbnail {
221             my ( $self, $offset, $filename ) = @_;
222              
223             my $off_val = $self->_validate_offset( $offset ) ? $offset : $self->offset;
224              
225             $self->output_file( $filename || $self->filename );
226             $self->options(
227             '-y', # overwrite files
228             '-f' => $self->file_format, # force format
229             '-vframes' => 1, # number of frames to record
230             '-ss' => $off_val, # position
231             '-s' => $self->output_width.'x'.$self->output_height, # sets frame size
232             '-loglevel'=> 'quiet', # tones down log output
233             );
234             return $self->hide_log_output ? capture { $self->ffmpeg->exec() } : $self->ffmpeg->exec() ;
235             }
236              
237              
238             =head2 _build_ffmpeg
239              
240             Creats a new FFmpeg::Command object, sets $self->video as the input_options, and executes to populate
241             $self->ffmpeg->stderr with the input video's meta data.
242              
243             =cut
244             sub _build_ffmpeg {
245             my ( $self ) = @_;
246             my $fmc = FFmpeg::Command->new() ;
247             $fmc->input_file( $self->video );
248             $fmc->execute();
249             return $fmc;
250             }
251              
252             =head2 _build_duration
253              
254             Builder for the "duration" attribute. Reads the length of the video from $self->ffmpeg->stderr
255             and converts it seconds.
256              
257             /Duration:\s+(\d+):(\d+):(\d+)(?:\.\d+)?\s*,/
258              
259             =cut
260              
261             sub _build_duration {
262             my ( $self ) = @_;;
263             my ( $h, $m, $s ) = $self->stderr() =~ /Duration:\s+(\d+):(\d+):(\d+)(?:\.\d+)?\s*,/s;
264             return $h * 3600 + $m * 60 + $s;
265             }
266              
267             =head2 _reset
268              
269             Clear the 'ffmpeg' and 'duration' attributes.
270              
271             =cut
272             sub _reset {
273             my ( $self ) = @_;
274             $self->clear_ffmpeg;
275             $self->clear_duration;
276             return 1;
277             };
278              
279             =head2 _validate_offset
280              
281             Checks $offset to make sure that it is numeric and <= $self->duration.
282              
283             =cut
284             sub _validate_offset {
285             my ($self, $offset ) = @_;
286             return $offset && looks_like_number( $offset ) and $offset <= $self->duration ;
287             }
288              
289              
290             =head1 SEE ALSO
291              
292             =over 4
293              
294             =item Video::Framegrab
295              
296             A frame-grabber / thumbnail-creator built around mplayer.
297              
298             =back
299              
300              
301             =head1 AUTHOR
302              
303             Brian Sauls, C<< <bbqsauls at cpan.org> >>
304              
305             =head1 BUGS
306              
307             Please report any bugs or feature requests to C<bug-video-thumbnail at rt.cpan.org>, or through
308             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Video-Thumbnail>. I will be notified, and then you'll
309             automatically be notified of progress on your bug as I make changes.
310              
311              
312              
313              
314             =head1 SUPPORT
315              
316             You can find documentation for this module with the perldoc command.
317              
318             perldoc FFmpeg::Thumbnail
319              
320              
321             You can also look for information at:
322              
323             =over 4
324              
325             =item * RT: CPAN's request tracker
326              
327             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Video-Thumbnail>
328              
329             =item * AnnoCPAN: Annotated CPAN documentation
330              
331             L<http://annocpan.org/dist/Video-Thumbnail>
332              
333             =item * CPAN Ratings
334              
335             L<http://cpanratings.perl.org/d/Video-Thumbnail>
336              
337             =item * Search CPAN
338              
339             L<http://search.cpan.org/dist/Video-Thumbnail/>
340              
341             =back
342              
343              
344              
345             =head1 LICENSE AND COPYRIGHT
346              
347             Copyright 2011 Brian Sauls, all rights reserved.
348              
349             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
350              
351             =cut
352              
353             no Moose;
354             __PACKAGE__->meta->make_immutable;
355              
356             1; # End of FFmpeg::Thumbnail