File Coverage

blib/lib/FLV/Splice.pm
Criterion Covered Total %
statement 64 69 92.7
branch 19 28 67.8
condition 8 14 57.1
subroutine 12 12 100.0
pod 3 3 100.0
total 106 126 84.1


line stmt bran cond sub pod time code
1             package FLV::Splice;
2              
3 1     1   54929 use warnings;
  1         2  
  1         30  
4 1     1   6 use strict;
  1         2  
  1         32  
5 1     1   27 use 5.008;
  1         3  
  1         45  
6              
7 1     1   519 use FLV::File;
  1         4  
  1         31  
8 1     1   7 use FLV::Util;
  1         3  
  1         137  
9 1     1   7 use List::MoreUtils qw(any);
  1         2  
  1         52  
10 1     1   7 use English qw(-no_match_vars);
  1         2  
  1         10  
11 1     1   544 use Carp;
  1         2  
  1         66  
12 1     1   7 use Readonly;
  1         3  
  1         728  
13              
14             our $VERSION = '0.24';
15              
16             =for stopwords FLVs codec AVC framerates
17              
18             =head1 NAME
19              
20             FLV::Splice - Concatenate FLV files into new files
21              
22             =head1 ACKNOWLEDGMENTS
23              
24             This feature was created with financial support from John Drago
25             (CPAN:JOHND). Thanks!
26              
27             =head1 LICENSE
28              
29             See L
30              
31             =head1 SYNOPSIS
32              
33             use FLV::Splic;
34             my $converter = FLV::Splice->new();
35             $converter->add_input('first.flv');
36             $converter->add_input('second.flv');
37             $converter->save('output.flv');
38              
39             =head1 DESCRIPTION
40              
41             Concatenates compatible FLV movies into a single file. In this
42             context, 'compatible' means that they have the same video and audio
43             codec. It is possible that this tool will produce unplayable movies,
44             for example concatenating AVC content will likely fail because each
45             segment has its own binary configuration block.
46              
47             This tool may also produce unplayable content if the segments have
48             different framerates. That depends on the player implementation.
49              
50             =head1 METHODS
51              
52             =over
53              
54             =item $pkg->new()
55              
56             Instantiate a converter.
57              
58             =cut
59              
60             sub new
61             {
62 5     5 1 8701 my $pkg = shift;
63              
64 5         22 my $start = { time => 0 };
65 5         40 my $self = bless {
66             start => 0,
67             nvideo => 0,
68             naudio => 0,
69             last_vid_time => 0,
70             last_aud_time => 0,
71             }, $pkg;
72 5         19 return $self;
73             }
74              
75             =item $self->add_input($flv_filename)
76              
77             =item $self->add_input($flv_instance)
78              
79             Open and append the specified FLV file. Alternatively, you may pass an
80             instantiated and parsed L instance.
81              
82             =cut
83              
84             sub add_input ## no critic (Complexity)
85             {
86 12     12 1 77 my $self = shift;
87 12         23 my $infile = shift;
88              
89 12         24 my $flv;
90 12 100 66     129 if (ref $infile && $infile->isa('FLV::File'))
91             {
92 8         45 $flv = $infile->clone;
93             }
94             else
95             {
96 4         32 $flv = FLV::File->new;
97 4         21 $flv->parse($infile);
98             }
99              
100 12 100       76 if ($self->{flv})
101             {
102             # add 2nd, 3rd, etc
103 7 50 50     48 if (($self->{flv}->get_header->has_video || 0) !=
      50        
104             ($flv->get_header->has_video || 0))
105             {
106 0         0 die 'One FLV has video and the other does not';
107             }
108 7 50 50     29 if (($self->{flv}->get_header->has_audio || 0) !=
      50        
109             ($flv->get_header->has_audio || 0))
110             {
111 0         0 die 'One FLV has audio and the other does not';
112             }
113 7         33 for my $tag ($flv->get_body->get_tags)
114             {
115 3045         5725 $tag->{start} += $self->{start};
116 3045         3535 push @{$self->{flv}->get_body->{tags}}, $tag;
  3045         8139  
117             }
118             }
119             else
120             {
121             # add 1st
122 5         16 $self->{flv} = $flv;
123             }
124              
125             # validate and count
126 12         239 for my $tag ($flv->get_body->get_tags)
127             {
128 5220 100       26390 if ($tag->isa('FLV::VideoTag'))
    100          
129             {
130 1788 100       5507 if (!$self->{nvideo}++)
    50          
131             {
132 5         28 $self->{video_codec} = $tag->{codec};
133             }
134             elsif ($tag->{codec} != $self->{video_codec})
135             {
136 0         0 die 'FLV has inconsistent video codecs';
137             }
138 1788         3743 $self->{last_vid_time} = $tag->{start};
139             }
140             elsif ($tag->isa('FLV::AudioTag'))
141             {
142 3420 100       11486 if (!$self->{naudio}++)
    50          
143             {
144 5         25 $self->{audio_codec} = $tag->{format};
145             }
146             elsif ($tag->{format} != $self->{audio_codec})
147             {
148 0         0 die 'FLV has inconsistent audio codecs';
149             }
150 3420         6116 $self->{last_aud_time} = $tag->{start};
151             }
152             }
153              
154 12 0 66     342 $self->{one_frame}
    50          
155             ||= 1 < $self->{nvideo} ? $self->{last_vid_time} / ($self->{nvideo} - 1)
156             : 1 < $self->{naudio} ? $self->{last_aud_time} / ($self->{naudio} - 1)
157             : die 'FLV has no media';
158              
159 12 50       49 $self->{start}
160             = ($self->{nvideo} ? $self->{last_vid_time} : $self->{last_aud_time})
161             + $self->{one_frame};
162              
163 12         247 return;
164             }
165              
166             =item $self->save($outfile)
167              
168             Serialize the combined FLV to file.
169              
170             =cut
171              
172             sub save
173             {
174 5     5 1 33 my $self = shift;
175 5         13 my $outfile = shift;
176              
177 5         48 my $outfh = FLV::Util->get_write_filehandle($outfile);
178 5 50       18 if (!$outfh)
179             {
180 0         0 die 'Failed to write FLV file: ' . $OS_ERROR;
181             }
182              
183 5         37 $self->{flv}->populate_meta();
184 5         37 $self->{flv}->serialize($outfh);
185              
186 5         392 return;
187             }
188              
189             1;
190              
191             __END__