- MC Tube
- FLV Injector tool
Actarus flv injector test: Improving and expanding the flv4php library (Version beta2)
We got a php alternative for video tag's injection: flv4php. The weakness of this project is the integration and you will have to guess from the source code how to really use it. The provided getID3 files joined with it, is clearly outdated so you will have to overrides some files with the newest getID3. However, be sure not to remplace all the files, only the audio-video part else flv4php will no work anymore.
History / Updates
27.01.2011: I discovered yamdi and of course added to my hall of fame for FLV injectors. Without any doubts, this is the coolest FLV injector of the world: two reasons, it has a better tag injection as we will see and it's opensource. Well done Ingo Oppermann! I have however two requests:
the custom injection directly from xml file.. Why? for completing missing tags and setting own record signatures like G00gle does (flvmdi is the only tool that open the door thanks to xtradata).No more the one, a patch allows this!Sorry ladies and gentlemen, it ignores the tags too :(..- ID3 tags support for mp3 audio directly in flv. Why will be like a jump to sky to port this feature using the ID3 support from getID3...Of course at the end, it's the Heaven if all is inegrated in getID3!
29.01.2011: I have registered Dave's player to osflash.org. Oh my God, there is a php injector flv4php! (will benchmark it). Guess What? its code is no more provided but I took Goldorak and fetched it. Holy shit, you have to register for an opensource file? how that can it be? No Way anymore for you as I mirrored all this here. Now what's up? I have looked at the flv4php code and the winner is...getID3! Yes, you read well, it's a php addon built on getID3!!! My (d/st)reams are coming true?
31.01.2011: flv4php roxx, it opens the door to the custom tag injection at least!!!!! Default tag detection has to be improved but it works :). I have also fixed the mp3 player, there is a limitation when reading ID3 tags: you will have to wait the file to be completely downloaded.
04.02.2011: Now, it's time for tagging tools to pass their exams. So if you are lost in the flv4php,yamdi,flvtool2,flvmdi maze, do not worry there is an exit!.
05.02.2011: Cuepoints are cool points for videos ;), I have added this as a bonus. This is not finished.
06.02.2011: Busy day with cuepoints but now, we got a least an auto cuepoint generator on the php side, downloadable and free of use (shipped with flvinjector 2.1)! Big discovery: flv1 is h263 encapsulated with the flv header, so when you encode with ffmpeg, don't use -vcodec h263 (or h263+) but -vcodec flv else you will got tagging problems with flvtool2 that will not recognize the flv (header) and generate an error!.
07.02.2011: Since my yesterday discovery: my advice for flv1 generation (if you need to inject tags behind with flvtool2) is to avoid avidemux that does not generate correct sorenson spark (codec is good but the flv header is missing!). Use ffmpeg instead but I warn you, the id3 tag injection is broken (I lost my afternoon trying to inject id3tags ^^').
09.02.2011: Please stay stuned because I am forking flv4php ^^ and it's core is not a piece of cake at all. Of course, it will use flvinfo core for a better tag injection/detection in the metadata and integrate flvcuepoints. I played a bit with RichFLV which opens the cut feature of flvtool2 to the H264 world :). The bad news for videos keyframes declared in the metadata, is that no tool agree each other on their values, whose calculation is right, I am really wondering now. I've finally succeeded to inject ID3 tags into H263 with FLVTool2 since yesterday, I will explain all this as soon as possible.
11.02.2011: I validated at least the times values by external means, don't miss it, it worth a banana not to use the bad liana. For this, I have built a tool to manipulate timecodes and keyframes :flvtimecodes
12.02.2011: MAJOR RELEASE of my flv tag injector (now 3.0) with some big surprises inside, run as fast as you can only one second left to get it (I am joking) in download of course.
13.02.2011: flvinjector-3.1 is out, now id3 tags can be injected to h264 flv as well, follow the interactive demo, it's fun!
14.02.2011: Woaw an interactive gui to tag flv (id3 only for now)! Where? in flvinjector-3.2, update your bits as you will get dynamically ffmpeg batchs!
16.02.2011: Two days means two new packages, doesn't it? Yes, I released the new flvinfo-3.0 that ends truely the fight with the h263/flv detection and improves riff support so you can know now if the video was produced by virtualdub =). The new flvinjector-4.0 solves xml bugs and makes cuepoints injection possible!
17.02.2011: flvinjector-4.1 solves xml bugs (again!) and adds a new architecture with a concept of plugins/extensions. cuepoints injection from .motn and .ass working!
18.02.2011: flvinjector-4.1 repacked to match version.
19.02.2011: I really hesitated vith the version number as flvinjector-4.2 brings major meta/cue/id3 tagging into reality with a nice html entry joined! The bad duck is keyframes generation...
28.02.2011: FFprobe confirms tbe timecodes values and frame number with a killing graph as bonus.
Tags
Tags allow to store extra informations of the file. For example, jpeg extra informations (author, size...) are saved in the exif header.This is very usefull when you got a lot of pictures and want to set copyrights and establish categories. For flash videos with the flv header, as we will see below in the table, all technical video settings is encoded in an info table.Note that getID3 provides an extra table with extended infos called infoset not shown here but in the example of flvinfo-3.0.Injection
Let's take the test.flv file provided in the fanno.dk's tutorial and analyse it with flvinfo to extract its video info table as a html table.It showed clearly that duration tag has a problem with its negative value and lasttimestamp has the same value.
video | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fileprops (thumb for this virtual tag) | duration | video data rate | lastkey frame time stamp | lastkey frame location | creator | metadata creator | has key frames | has metadata | key frames | width | height | metadata date | data size | audio codec id | audio data rate | audio size | video size | file size | last time stamp | audio delay | encoder | creation date | xtra data | album | artist | album_artist | composer | disc | TYER | genre | title | track |
-12.179 | 287.05 | 4671 | 7305327 | FLV Editor for PHP V0.21 (Project: Flv4php) | FLV Editor for PHP V0.21 (Project: Flv4php) | 1 | 1 | Array(1) | 320 | 240 | 1296539613000 | 571 | 0 | 0.00 | 0 | 156799 | 157379 | -12.179 |
Let's decide to fix this with our hacked injector. The first thing to do is to clear tags from the file because if you do so, flv4php will read this time correctly the duration value!. I have done this using yamdi :
yamdi -i test.flv -M -o test_clean.flvgiving this info table (Oh my God, YAMDI has ejected Goldorak's tags from its video spaceship!
video | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fileprops (thumb for this virtual tag) | duration | video data rate | lastkey frame time stamp | lastkey frame location | creator | metadata creator | has key frames | has metadata | key frames | width | height | metadata date | data size | audio codec id | audio data rate | audio size | video size | file size | last time stamp | audio delay | encoder | creation date | xtra data | album | artist | album_artist | composer | disc | TYER | genre | title | track |
and then reinject the tags with the fixed value thanks to our hacked injector:
/** * fix_metadata.php, a php flv injector fixer helper by Actarus * * requires flv4php with an updated getId3! * V1.0 (04.02.2011) **/ $path = '<your_video_dir>'; // Path to flv files (could be behind web root) $demo=false; if( !isset($_GET["file"]) ) { $_GET["file"]="test_clean.flv"; //die(header("HTTP/1.0 404 Not Found"));goldorak_h264 $demo=true; } $file = $path . htmlspecialchars($_GET["file"]); if( !isset($_GET["type"]) ) $_GET["type"]='inject'; require_once('lib/flv4php_php4/FLV.php'); // Path to flv.php / (flv4php) if ( file_exists($file) ) { $flv = new FLV($file); //read and decodes meta tags from the flv $meta=$flv->getMetaData(); $newMetaData=$meta->data; //now inject your custom tags here //Fix negative duration and lastimestamp..(getMetaData() is buggy when this tag is already defined!) $newMetaData["duration"]=5.005; //This is the "playtime_seconds" value read with flv4php from test_cleaned.flv generated with yamdi -i test.flv -M -o test_cleaned.flv $newMetaData["lasttimestamp"]=$newMetaData["duration"]; $newMetaData["creator"]= makeblink("Goldorak's injector!"); $newMetaData["metadatacreator"]="FLV Editor for PHP V0.21a (Project: Flv4php)"; //the surprise..the famous tags are not read by getMetaData, seems we have to handle here.. $newMetaData["haskeyframes"]=(array_key_exists("keyframes",$newMetaData)&&(is_array($newMetaData["keyframes"])&&(count($newMetaData["keyframes"])>1))) ? '1' : '0'; $newMetaData["hasmetadata"]='1'; //silly tag imho, because dude, you are one! $newMetaData["hasKeyframes"]=$newMetaData["haskeyframes"]; $newMetaData["hasMetadata"]=$newMetaData["hasmetadata"]; if($_GET["type"]=="preview") { echo "<pre>"; print_r($newMetaData); echo "</pre>"; }else { //encodes MetaData into amf structure $metadata = $flv->createMetaData($newMetaData); //generates the flv file with the new injected metadata //!TODO: let the choice to write directly to the disk.. $flv->playFlv(1, 0,$newMetaData,$merge = false); } } else { die(header("HTTP/1.0 404 Not Found")); }If you want to inject default tags instead, here is the injector code:
/** * inject_metadata.php, a php flv injector helper by Actarus * * requires flv4php with an updated getId3! * V1.0 (30.01.2011) **/ $path = '<your_video_dir>'; // Path to flv files (could be behind web root) $_GET["file"]="goldorak_h264.flv"; //Comment this line, equivalent to inject_metadata.php?file=goldorak_h264.flv if( !isset($_GET["file"]) ) die(header("HTTP/1.0 404 Not Found")); $file = $path . htmlspecialchars($_GET["file"]); // 'type=inject' is by default, it will inject the tags and you will be able to download the updated flv file. Use 'type=preview' in the url to dump. if( !isset($_GET["type"]) ) $_GET["type"]='inject'; require_once('lib/flv4php_php4/FLV.php'); // Path to flv.php / (flv4php) if ( file_exists($file) ) { $flv = new FLV($file); //read and decodes default meta tags $newMetaData = $flv->defaultMetaData(true); //now inject your custom tags here //!TODO: read this from the xml file //Please use your wished values, this is a dummy sample $newMetaData['hasKeyframes']=makeblink('+'); $newMetaData['hasVideo']=makeblink('1'); $newMetaData['hasAudio']=makeblink('1'); $newMetaData['hasMetadata']=makeblink('1'); $newMetaData['canSeekToEnd']=makeblink('+'); $newMetaData['datasize']=makeblink('+'); $newMetaData['videosize']=makeblink('+'); $newMetaData['audiosize']=makeblink('+'); $newMetaData['lasttimestamp']=makeblink('+'); $newMetaData['lastkeyframetimestamp']=makeblink('+'); $newMetaData['lastkeyframelocation']=makeblink('+'); $newMetaData['keyframes']=makeblink('+'); $newMetaData['audiodelay']=makeblink('+'); $newMetaData['creationdate']=makeblink('+'); $newMetaData['xtradata']=makeblink('+'); $newMetaData['album']=makeblink('+'); $newMetaData['artist']=makeblink('+'); $newMetaData['album_artist']=makeblink('+'); $newMetaData['composer']=makeblink('+'); $newMetaData['disc']=makeblink('+'); $newMetaData['TYER']=makeblink('+'); $newMetaData['genre']=makeblink('+'); $newMetaData['title']=makeblink('+'); $newMetaData['track']=makeblink('+'); $newMetaData['creator']=makeblink("Goldorak's injector!"); if($_GET["type"]=="preview") { echo "<pre>"; print_r($newMetaData); echo "</pre>"; }else { //encodes MetaData into amf structure $metadata = $flv->createMetaData($newMetaData); //generates the flv file with the new injected metadata //!TODO: let the choice to write directly to the disk.. $flv->playFlv(1, 0,$newMetaData,$merge = true); } } else { die(header("HTTP/1.0 404 Not Found")); } ?>An the goldorak's part? Sure, here it is:
/** The two functions here are the core of theLet's read the fixed flv:tag injectiondemo of course **/ function rainbow($text,$factor=0.4) { //--------------------------------- $colors=array("FFFF00","66FF99","33FF33","66FFFF","33CCFF","3366FF","CC33CC","993366","990000","CC0000","FF0000"); $b=4; $c=0; $t=0; $tMax=strlen(utf8_decode($text)); $cMax=count($colors); $rText=array(); while(($c<$cMax)&&($t<$tMax)) { $rText[$t]='<font color="#'.$colors[floor($c*$factor)+$b].'">'.$text[$t].'</font>'; $c++; $t++; if(($b+$c)>$cMax) $c=0; } $text=implode('',$rText); return $text; } function makeblink($code) { //------------------------- $size=strlen($code); if($size>1) { $size=7; $code=rainbow($code); } return '<font color="blue"><blink><marquee style="width:'.$size.'em;">'.$code.'</marquee></blink></font>'; }
video | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fileprops (thumb for this virtual tag) | duration | video data rate | lastkey frame time stamp | lastkey frame location | creator | metadata creator | has key frames | has metadata | key frames | width | height | metadata date | data size | audio codec id | audio data rate | audio size | video size | file size | last time stamp | audio delay | encoder | creation date | xtra data | album | artist | album_artist | composer | disc | TYER | genre | title | track |
-12.179 | 287.05 | 4671 | 7305327 | FLV Editor for PHP V0.21 (Project: Flv4php) | FLV Editor for PHP V0.21 (Project: Flv4php) | 1 | 1 | Array(1) | 320 | 240 | 1296539613000 | 571 | 0 | 0.00 | 0 | 156799 | 157379 | -12.179 | ||||||||||||||
5.005 | 287.05 | 4671 | 7305327 | FLV Editor for PHP V0.21a (Project: Flv4php) | Array(1) | 320 | 240 | 2011-02-01T06:53:33.-392Z | 571 | 0 | 0.00 | 0 | 156799 | 157379 | 5.005 |
Key frames support
Let's check this by having a look to the keyframes generated by all the stuff we got under the hand. According what I have said before on codec compatibility, we can do this only on H263 based videos files. This is good as test.flv is one :)
Validation (timecodes only)
As I was fed up with all these incoherencies, I looked for a way to validate this part, the good new is I found a way to validate the timecodes but the bad news is not for filepositions (as I did NOT succeed to compile ffmpegsource2, having no source of the original ffmpegsource 1.3). You will be suprised as well by the way I have done this. To start, I have used virtualdub with plugins for flv that worked only for h263/vp6. At this time, we got only two and they provides indirectly timecodes because you will have to manualy jump between each keyframe and write it down. Fortunately, there were only 9 keyframes in test_clean.flv so it wasn't so painfull. Here are the xml results following the scheme of an extended format of the metadata's timescodes I created for the occasion: I have introduced version and id and type attributes for the time element and name for the value element. This last attribute's value matches the frame number of the key.
flv test_clean_flv.vdplugin_timecodes.xml | FLVInputDriver test_clean_FLVInputDriver.vdplugin_timecodes.xml |
---|---|
<!-- Manually extracted with flv.vdplugin 1.3 (FccHandler) http://fcchandler.home.comcast.net/~fcchandler/Plugins/FLV/index.html Version 1.3 (December 24, 2010): 24.975fps , Datarate=245kbps - 126 frames last is 5045 --> <times id="flv.vdplugin" type="keyframes" version="1.3"> <value id="0" name="0">0</value> <value id="1" name="36">1.441</value> <value id="2" name="37">1.481</value> <value id="3" name="38">1.522</value> <value id="4" name="40">1.602</value> <value id="5" name="70">2.803</value> <value id="6" name="101">4.044</value> <value id="7" name="116">4.645</value> <value id="8" name="117">4.685</value> </times> |
<!-- Manually with FLVInputDriver.vdplugin (http://moitah.net/) 1.1.0 (2008-May-07): H.263 / VP6 + MP3 / PCM . File: test_clean.flv - 151 frames last is 5038 Estimated True Frame Rate: 29,940119760479 (5000/167) Average Frame Rate: 24,975024975025 (25000/1001) --> <times id="FLVInputDriver.vdplugin" type="keyframes" version="1.1.0"> <value id="0" name="0">0</value> <value id="1" name="43">1.435</value> <value id="2" name="44">1.468</value> <value id="3" name="46">1.535</value> <value id="4" name="48">1.602</value> <value id="5" name="84">2.803</value> <value id="6" name="121">4.037</value> <value id="7" name="139">4.638</value> <value id="8" name="140">4.671</value> </times> |
ffmpegsource test_clean_ffmpegsource_frames.txt | aegisub test_clean.ass |
---|---|
<!-- Generated from test_clean_ffmpegsource_frames.txt, 9 frame(s) found--> <times id="ffmpegsource" type="keyframes" version="1.13"> <value id="0" name="0">0</value> <value id="1" name="36">1.435</value> <value id="2" name="37">1.468</value> <value id="3" name="38">1.535</value> <value id="4" name="40">1.601</value> <value id="5" name="70">2.803</value> <value id="6" name="101">4.037</value> <value id="7" name="116">4.638</value> <value id="8" name="117">4.671</value> </times> |
<!-- Generated from test_clean_aegisub_frames.txt, 9 frame(s) found--> <times id="aegisub" type="keyframes" version="2.1.8"> <value id="0" name="0">0</value> <value id="1" name="36">1.435</value> <value id="2" name="37">1.468</value> <value id="3" name="38">1.535</value> <value id="4" name="40">1.601</value> <value id="5" name="70">2.803</value> <value id="6" name="101">4.037</value> <value id="7" name="116">4.638</value> <value id="8" name="117">4.671</value> </times> |
php4ffprobe test_clean_ffprobe_timecodes.phps | |
<!-- Manually converted from php array generated with test_clean_ffprobe_timecodes.phps --> <times id="php4ffprobe" type="keyframes" version="4.0"> <value id="0" name="0">0</value> <value id="1" name="36">1.435</value> <value id="2" name="37">1.468</value> <value id="3" name="38">1.535</value> <value id="4" name="40">1.601</value> <value id="5" name="70">2.803</value> <value id="6" name="101">4.037</value> <value id="7" name="116">4.638</value> <value id="8" name="117">4.671</value> </times> |
Final conclusion
If you have to use virtualdub to manipulate flv1/h263 files, better use ffmpegsource (not ffmepgsource2 bringing ffms2.dll that really sucks, got errors when loading avs and compiling due to broken postprocessing) through an avisynth script because both flv plugins are buggy somehow (the winner equation is fccHandler's frame numbers+Moitah's timecodes=ffmpegsource's frame numbers/timecodes). Yamdi need to fix its timecodes values to be great, richFLV has incoherent timecodes but as it does not inject keyframes metatags, I don't mind. Unless I find a way to validate filepositions, better use flvtool2 or flvmdi to inject keyframes for h263 and Yamdi for h264 or my injector when keyframes will be handled ;).
Coherency check
To do this, let's compare all the video tagged files (I have removed most of the tags not related to video or to frame)
meta | infoset | infoset->flv->header | infoset->flv->meta | infoset->flv->video | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fileprops (thumb for this virtual tag) | metadata creator | has Key frames | has Video | has Audio | has Meta data | can Seek To End | duration | data size | video size | frame rate | video data rate | video codec id | file size | last time stamp | lastkey frame time stamp | lastkey frame location | key frames | metadata date | creator | cuePoints | has key frames | has CuePoints | file size | avdataoffset | avdataend | video | play time_seconds | bit rate | play time_string | signature | version | has Audio | has Video | video SizeType | onMetaData | video Codec |
FLV Editor for PHP V0.21a (Project: Flv4php) | 5.005 | 571 | 156799 | 287.05 | 157379 | 5.005 | 4671 | 7305327 | Array(1) | 2011-02-01T06:53:33.-392Z | 158033 | 0 | 158033 | Array(7) | 5.005 | 206040.41720991 | 0:05 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ||||||||||||
Yet Another Metadata Injector for FLV - Version 1.7a | 1 | 1 | 1 | 5.005 | 156803 | 156299 | 25.174825174825 | 241.81 | 2 | 157468 | 5.005 | 4.671 | 145337 | Array(9) | 157468 | 0 | 157468 | Array(8) | 5.005 | 205303.7809648 | 0:05 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ||||||||
Manitu Group FLV MetaData Injector 2 | 5.005 | 681 | 156803 | 25.2 | 0.00 | 2 | 157497 | 5.005 | 4.671 | Array(9) | 1296844221499 | 157497 | 0 | 157497 | Array(8) | 5.005 | 205341.59061278 | 0:05 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | |||||||||||
inlet media FLVTool2 v1.0.6 - http://www.inlet-media.de/flvtool2 | 1 | 1 | 1 | 5.038 | 157156 | 156299 | 30 | 247.61 | 2 | 157681 | 5.005 | 4.671 | Array(9) | 1296829221125 | Array(0) | 157681 | 0 | 157681 | Array(8) | 5.038 | 205581.4863103 | 0:05 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Analysis
Flvtool2 seems to be the best alternative to tag h263 videos mainly because it positionnates correctly the "has flag" tags, inject the keyframes and it is the only tool that has also the cuePoint feature (I dumped the array here, its empty so I don't know what to think about it for now).
- FLV4PHP:framerate is lost..it's the only tool that fill correctly the audiocodecid tag.
- YAMDI: metadatadate is mssing and this tool seems to have no audio tag support, maybe for future release?
- FLVTOOL2: I have detected a incoherency in Flvtool2 tag generation: the 'audiocodecid' tag produces a warning in GetID3 because the value given is an empty array instead of an integer!
- FLVMDI: this tool forget to set the has flags...and set videodatarate incorrectly. The tool version number is missing in the metadatacreator this is a bad stategy imho. I have used the 2.96 here.
Cuepoints (Bonus)
Cuepoints are strategic so I can't avoid talking about them. By putting markers in the video file (step two) from a marker config file (step one), you provide the cut facility behind(step three). Of course, for a paranoid like me, an extra step, the check (step four) is a must.Thus cuepoints are useful when you want to produce some video footage or extract some important scenes for a demo.
<?php
//======sample 2 in flvtool2 source (more interesting as it shows the overwrite process)
//include my cuepoint generator (included in flvinjector >= 2.0)
require_once('lib/flvcuepoint.php');
//this function is stored in "flvcuepoint_sample2.php";
function build_ozml_flvtool2_sources($filename) {
//------------------------------------------
$o=getOzml($filename);
$label="TestEvent1";
$inpoint=8.325;
$speaker="Peter";
$says="Hello my name is Peter.";
addEventTimeMarker($o,$label,$inpoint,$speaker,$says);
$label="TestEvent2";
$inpoint=25;
$index=1;
$title="Chapter 1";
addNavigationTimeMarker($o,$label,$inpoint,$index,$title) ;
$label="TestEvent3";
$inpoint=25; //same inpoint as previous, this will override "TestEvent2"
$index=2;
$title="Chapter 2";
addNavigationTimeMarker($o,$label,$inpoint,$index,$title) ;
//magic call..
return xml_ident(mc_($o,'','')); // xml_ident(
}
//configure output files
$ozmlfile="motn/cuepoint2.xml"; //generated from php, input
$flv2file="cuepoints/cuepoint2.xml";//converted from php, output
//Generate the motn/ozml file
$ozml=build_ozml_flvtool2_sources($ozmlfile);
//show it
echo("<pre>");
echo(xml_highlight($flvml));
echo("</pre>");
//convert to flvtool2 xml format and save it to disk
$flvml=convert_cuepoint_xml($xml_dir.$ozmlfile);
file_put_contents($xml_dir.$flv2file,$flvml);
?>
Source file, .motn file cuepoint2.xml generated from the php above | flv2tool cuepoint file cuepoint2.xml | |
---|---|---|
<ozml version="2.0"> <factory id="Actarus" uuid="31a262d6247f3513b19d1149102e116d"> <description>Cuepoint file for motn/cuepoint2.xml</description> <manufacturer>php cuepoint generator for flvtool2</manufacturer> <version>1.MC</version> </factory> <scene name="flv cuepoint demo" id="goldorak" factoryID="Actarus" version="1.0"> <timemarkerset> <timemarker> <label>TestEvent1</label> <inpoint>8.325</inpoint> <parameter name="speaker" value="Peter"/> <parameter name="says" value="Hello my name is Peter."/> </timemarker> <timemarker> <label>TestEvent2</label> <inpoint>25</inpoint> <parameter name="index" value="1"/> <parameter name="title" value="Chapter 1"/> </timemarker> <timemarker> <label>TestEvent3</label> <inpoint>25</inpoint> <parameter name="index" value="2"/> <parameter name="title" value="Chapter 2"/> </timemarker> </timemarkerset> </scene> </ozml> |
==PHP/XSLT Bridge==> |
<?xml version="1.0" encoding="utf-8"?> <!--source="download/flvinjector/motn/cuepoint2.xml"--> <tags> <metatag event="onCuePoint" overwrite="true"> <name>TestEvent1</name> <timestamp>333</timestamp> <parameters> <speaker>Peter</speaker> <says>Hello my name is Peter.</says> </parameters> <type>event</type> </metatag> <metatag event="onCuePoint" overwrite="true"> <name>TestEvent2</name> <timestamp>1000</timestamp> <parameters> <index>1</index> <title>Chapter 1</title> </parameters> <type>navigation</type> </metatag> <metatag event="onCuePoint" overwrite="true"> <name>TestEvent3</name> <timestamp>1000</timestamp> <parameters> <index>2</index> <title>Chapter 2</title> </parameters> <type>navigation</type> </metatag> </tags> |
where XSLT used for the bridge is a goldorak's improvement of the osflash script cuemotn.xsl |
<?xml version="1.0" encoding="utf-8"?> <!-- Here's another xslt-script which generates FLVTool2 cuepoints from Motion project-files (*.motn), --> <!-- tested with Apple Motion 2.0.1. Use the generated XML like flvtool2 -AUPktv mymeta.cue.xml test.flv testout.flv. --> <!-- patch update by Actarus from sample http://osflash.org/flvtool2-scripts on 06.02.2011--> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" indent="yes"/> <xsl:preserve-space elements="*"/> <xsl:param name="name">motn/cuepoint2.xml</xsl:param> <xsl:param name="fps">25</xsl:param> <xsl:template match="/ozml"> <xsl:comment>source="<xsl:copy-of select="$name"/>"</xsl:comment> <tags> <xsl:for-each select="./scene/timemarkerset/timemarker"> <metatag event="onCuePoint" overwrite="true"> <name><xsl:value-of select="./label/text()" /></name> <timestamp><xsl:value-of select="round(./inpoint/text() div $fps * 1000)" /></timestamp> <xsl:if test="./parameter"> <parameters> <xsl:for-each select="./parameter"> <xsl:variable name="name" select="@name"/> <xsl:element name="{$name}"> <xsl:value-of select="@value"/> </xsl:element> </xsl:for-each> </parameters> </xsl:if> <xsl:choose> <xsl:when test="./parameter[@name='index']"> <type>navigation</type> </xsl:when> <xsl:otherwise> <type>event</type> </xsl:otherwise> </xsl:choose> </metatag> </xsl:for-each> </tags> </xsl:template> </xsl:stylesheet> |
flvtool2 -AUt cuepoint2.xml test_inject_flv2.flv test_cueinject_flv2.flv flvtool2 -Px test_cueinject_flv2.flv > test_flv2cue2.xml
flvtool2 -CU -o 2000 example.flv
to finish, we make some checks behind.
Generated and read from cuepoint2.xml | read from getID3 |
---|---|
Array ( [0] => Array ( [name] => TestEvent1 [time] => 0 [parameters] => Array ( [speaker] => Peter [says] => Hello my name is Peter. ) [type] => event ) [1] => Array ( [name] => TestEvent3 [time] => 1 [parameters] => Array ( [title] => Chapter 2 [index] => 2 ) [type] => navigation ) ) |
Array ( [0] => Array ( [name] => TestEvent1 [time] => 0 [parameters] => Array ( [speaker] => Peter [says] => Hello my name is Peter. ) [type] => event ) [1] => Array ( [name] => TestEvent3 [time] => 1 [parameters] => Array ( [title] => Chapter 2 [index] => 2 ) [type] => navigation ) ) |
Analysis
Will come soon
Conclusion
Let's imagine we integrate the yamdi features into flv4php (and vice versa) with the cuepoint of flvtool2 and we have clearly killing tools to manipulate flv videos. Due to the headaches I have got to make flv4php working and as I want to avoid you this pain too, you can the download the goldorak's flv injector here.