File Coverage

blib/lib/FLV/Tag.pm
Criterion Covered Total %
statement 73 77 94.8
branch 8 14 57.1
condition 6 17 35.2
subroutine 14 14 100.0
pod 4 4 100.0
total 105 126 83.3


line stmt bran cond sub pod time code
1             package FLV::Tag;
2              
3 6     6   35 use warnings;
  6         12  
  6         185  
4 6     6   31 use strict;
  6         10  
  6         163  
5 6     6   103 use 5.008;
  6         18  
  6         545  
6 6     6   31 use Carp;
  6         10  
  6         762  
7 6     6   33 use English qw(-no_match_vars);
  6         11  
  6         40  
8              
9 6     6   4410 use base 'FLV::Base';
  6         11  
  6         481  
10              
11 6     6   4768 use FLV::Util;
  6         16  
  6         1612  
12 6     6   4713 use FLV::AudioTag;
  6         54  
  6         251  
13 6     6   4756 use FLV::VideoTag;
  6         17  
  6         167  
14 6     6   4698 use FLV::MetaTag;
  6         19  
  6         4265  
15              
16             our $VERSION = '0.24';
17              
18             =for stopwords subtag
19              
20             =head1 NAME
21              
22             FLV::Tag - Flash video file data structure
23              
24             =head1 LICENSE
25              
26             See L
27              
28             =head1 METHODS
29              
30             This is a subclass of L.
31              
32             =over
33              
34             =item $self->parse($fileinst)
35              
36             =item $self->parse($fileinst, {opt => $optvalue, ...})
37              
38             Takes a FLV::File instance and extracts an FLV tag from the file
39             stream. This method then multiplexes that tag into one of the
40             subtypes: video, audio or meta. This method throws exceptions if the
41             stream is not a valid FLV v1.0 or v1.1 file.
42              
43             At the end, this method stores the subtag instance, which can be
44             retrieved with get_payload().
45              
46             There is no return value.
47              
48             An option of C 1> causes the byte offset of the
49             tag to be stored in the instance. This is intended for testing and/or
50             debugging, so there is no public accessor for that property.
51              
52             =cut
53              
54             sub parse
55             {
56 16249     16249 1 21522 my $self = shift;
57 16249         17851 my $file = shift;
58 16249         17368 my $opts = shift;
59 16249   50     53130 $opts ||= {};
60              
61 16249         49777 my $content = $file->get_bytes(11);
62              
63 16249         23752 my ($type, @datasize, @timestamp);
64             (
65 16249         71310 $type, $datasize[0], $datasize[1], $datasize[2],
66             $timestamp[1], $timestamp[2], $timestamp[3], $timestamp[0]
67             ) = unpack 'CCCCCCCC', $content;
68              
69 16249         43327 my $datasize = ($datasize[0] * 256 + $datasize[1]) * 256 + $datasize[2];
70 16249         25268 my $timestamp
71             = (($timestamp[0] * 256 + $timestamp[1]) * 256 + $timestamp[2]) * 256 +
72             $timestamp[3];
73              
74 16249 50 33     73490 if ($timestamp > 4_000_000_000 || $timestamp < 0)
75             {
76 0         0 warn "Funny timestamp: @timestamp -> $timestamp\n";
77             }
78              
79 16249 50       29957 if ($datasize < 11)
80             {
81 0         0 die "Tag size is too small ($datasize) at byte " . $file->get_pos(-10);
82             }
83              
84 16249         80449 my $payload_class = $TAG_CLASSES{$type};
85 16249 50       117541 if (!$payload_class)
86             {
87 0         0 die "Unknown tag type $type at byte " . $file->get_pos(-11);
88             }
89              
90 16249         48874 $self->{payload} = $payload_class->new();
91 16249         43572 $self->{payload}->{start} = $timestamp; # millisec
92 16249 100       35867 if ($opts->{record_positions})
93             {
94              
95             # for testing/debugging only!
96 870         2500 $self->{payload}->{_pos} = $file->get_pos(-11);
97 870         3718 $self->{payload}->{_pos} =~ s/\D.*\z//xms;
98             }
99 16249         53546 $self->{payload}->parse($file, $datasize); # might throw exception
100              
101 16249         48237 return;
102             }
103              
104             =item $self->get_payload()
105              
106             Returns the subtag instance found by parse(). This will be instance
107             of FLV::VideoTag, FLV::AudioTag or FLV::MetaTag.
108              
109             =cut
110              
111             sub get_payload
112             {
113 16249     16249 1 21491 my $self = shift;
114 16249         61390 return $self->{payload};
115             }
116              
117             =item $pkg->copy_tag($old_tag, $new_tag)
118              
119             Perform a generic part of the clone behavior for the tag subtypes.
120              
121             =cut
122              
123             sub copy_tag {
124 3480     3480 1 5055 my $pkg_or_self = shift;
125 3480   33     8283 my $old_tag = shift || croak 'Please specify a tag';
126 3480   33     7138 my $new_tag = shift || croak 'Please specify a tag';
127 3480         10911 for my $key (qw( start )) {
128 3480         12428 $new_tag->{$key} = $old_tag->{$key};
129             }
130 3480         12501 return;
131             }
132              
133             =item $pkg->serialize($tag, $filehandle)
134              
135             =item $self->serialize($tag, $filehandle)
136              
137             Serializes the specified video, audio or meta tag. If that
138             representation is not complete, this throws an exception via croak().
139             Returns a boolean indicating whether writing to the file handle was
140             successful.
141              
142             =cut
143              
144             sub serialize
145             {
146 9186     9186 1 11855 my $pkg_or_self = shift;
147 9186   33     20221 my $tag = shift || croak 'Please specify a tag';
148 9186   33     17681 my $filehandle = shift || croak 'Please specify a filehandle';
149              
150 9186         30355 my $tag_type = { reverse %TAG_CLASSES }->{ ref $tag };
151 9186 50       287385 if (!$tag_type)
152             {
153 0         0 die 'Unknown tag class ' . ref $tag;
154             }
155              
156 9186         31240 my @timestamp = (
157             $tag->{start} >> 24 & 0xff,
158             $tag->{start} >> 16 & 0xff,
159             $tag->{start} >> 8 & 0xff,
160             $tag->{start} & 0xff,
161             );
162 9186         27761 my $data = $tag->serialize();
163 9186         14182 my $datasize = length $data;
164             my @datasize
165 9186         19005 = ($datasize >> 16 & 0xff, $datasize >> 8 & 0xff, $datasize & 0xff);
166              
167 9186         32358 my $header = pack 'CCCCCCCCCCC', $tag_type, @datasize, @timestamp[1 .. 3],
168             $timestamp[0], 0, 0, 0;
169 9186 50       11719 return if (!print {$filehandle} $header);
  9186         27409  
170 9186 50       11608 return if (!print {$filehandle} $data);
  9186         74614  
171 9186         39702 return 11 + $datasize;
172             }
173              
174             1;
175              
176             __END__