Когда я использую модуль FLV::Info
для извлечения метаданных или объединения нескольких файлов FLV, я часто получаю сообщение об ошибке «Размер тега слишком мал», и тогда модуль просто отказывается работать.Кто-то опубликовал отчет об ошибке здесь три года назад, но, похоже, нет исправления.
Что ж, недавно я обнаружил, что просто закомментирую следующие строки кода в Tag.pmодин из модулей зависимостей FLV::Info
, например, так:
=pod
if ($datasize < 11)
{
die "Tag size is too small ($datasize) at byte " . $file->get_pos(-10);
}
=cut
FLV::Info
с готовностью выполнит работу, как и ожидалось.
Я не уверен, что это оченьтупой вопрос, но мне любопытно:
Есть ли простой способ изменить пару строк кода в загруженном модуле без изменения исходного файла .pm?
Любые идеи, предложения или комментарии?Спасибо, как всегда:)
ОБНОВЛЕНИЕ
Большое спасибо @Shwern.Ваш ответ очень радует :) Также спасибо @DVK за предложение и термин «monkey patch» и @brian за рекомендацию к книге.
Вот мой отзыв о тестах на примере FLV-файла, которые меня бросилиОшибка «Размер тега слишком мал», если я использую оригинальный модуль, ничего не делая с ним.
Подход «eval it back» решает проблему
use FLV::Info;
use Data::Dump::Streamer;
my $original = FLV::Tag->can("parse");
my $code = Dump($original)->Out;
#$code =~ s{\Qif ($datasize < 11)\E}{if (0)}; #This somehow won't work
$code =~ s{die "Tag}{warn "Tag}; #Let it warn but not die
no warnings 'redefine';
*FLV::Tag::parse = eval $code;
my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();
Подход "overide die to die" также работает
BEGIN {
*CORE::GLOBAL::die = sub { return CORE::die(@_) };
}
use FLV::Info;
{
local *CORE::GLOBAL::die = sub {
return if $_[0] =~ /^Tag size is too small/;
return CORE::die(@_);
};
my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();
}
Подход "redefine", однако, не работает, как я ожидал.
Я скопировал и вставил оригинальную подпрограмму FLV :: Tag :: parse и закомментировал строки кода точно так же, как я изменил исходный файл Tag.pm следующим образом:
use FLV::Info;
no warnings 'redefine';
*FLV::Tag::parse = sub {
...
...
=pod
if ($datasize < 11)
{
die "Tag size is too small ($datasize) at byte " . $file->get_pos(-10);
}
=cut
...
...
};
my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();
но я получил эту ошибку:
Unknown tag type 18 at byte 13 (0xd)
Хорошо, даже если копировать и вставить точно такую же подпрограмму синтаксического анализа без каких-либо изменений в моем переопределении, я получаю ошибку "Неизвестный тип тега" вместо "Размер тега слишком мал ".
Это страНге!
Для справки, подходы "eval it back" и "override die to not die" даст мне следующее:
1992 video frames
File name sample.flv
File size 5767831 bytes
Duration about 79.6 seconds
Video 1992 frames
codec AVC
type interframe/keyframe
Audio 1712 packets
format AAC
rate 44100 Hz
size 16 bit
type stereo
Meta 1 event
audiocodecid 10
audiosamplerate 22050
audiosamplesize 16
audiosize 342817
creationdate unknown
datasize 805
duration 79.6
filesize 5767869
framerate 25
height 300
keyframes {
>>> 'filepositions' => [
>>> '780',
>>> '865',
>>> '1324122',
>>> '2348913',
>>> '2978630',
>>> '3479001',
>>> '3973756',
>>> '4476281',
>>> '4997226',
>>> '5391890'
>>> ],
>>> 'times' => [
>>> '0',
>>> '0',
>>> '9.6',
>>> '19.2',
>>> '28.8',
>>> '38.4',
>>> '46.32',
>>> '55.92',
>>> '64.88',
>>> '73.88'
>>> ]
>>> }
lastkeyframetimestamp 73.88
lasttimestamp 79.6
metadatacreator Manitu Group FLV MetaData Injector 2
metadatadate 1281964633858
stereo 1
videocodecid 7
videosize 5424234
width 400
FINAL UPDATE
Я выяснил, почему подход «переопределить» потерпел неудачу, включив строгую прагму и предупреждения.Спасибо @Schwern за напоминание:)
Сначала добавьте следующие строки кода (скопированные из модуля FLV :: Util), а затем выполните переопределение подпрограммы FLV :: Tag :: parse.
Readonly::Hash our %TAG_CLASSES => (
8 => 'FLV::AudioTag',
9 => 'FLV::VideoTag',
18 => 'FLV::MetaTag',
);