2009-01-06

osTube2.3--取得上傳flv檔的時間長度

想不到今天上班閒時間多,本想說都快學期末了,學生可能找麻煩的會比較多,沒想到至目前為止只能說一個「還好」,看來有hinet真的省了很多麻煩。

言歸正傳…
osTube嚴格來說,能算「好用」,但不太「適用」。就以目前使用的狀況來看,有蠻多東西反倒是要我們去習慣osTube…比如之前的一些bug、flvplayer中文問題、多格式的轉檔與flv上傳的時間長度…

就目前我自己本身來說,除了flvplayer的中文顯示可能無法直接修正之外(因為可能要改player的內碼),大部份的問題都已正式解決,今日就來解說flv上傳時的時間長度的取得。

=============叫我分隔線===============
事實上,flv(或多媒體檔案)這類檔案,其檔案內容已存有所謂的tag,或叫檔頭的東西,這一些東西內記錄著「格式」、「版本」、「比特率」、「fps」、「播放時間」、「長度」…等,你從一般播放器的媒體資訊的東西也都是在這一些tag中取得的。今天,我就利用方便的google大神在網路上找到一些好像的function或plugin來替我們的osTube在flv的metadata中增益。


首先,先分析一下flv在整個osTube中的上傳動作是怎麼進行的。
開啟ostube目錄底下的upload.php,可以在大約49x或5xx行的地方找到「elseif($fileFormat == "flv")」,由此處可以知道,flv並不會特別的經過轉檔的方式來儲存,而是直接由上傳時就從tmp複製到所屬的媒體資料匣,所以,特別的動作只需在upload.php中來進行。

先在upload.php的內容最後,加上一個function…內容如下
//判斷flv影片長度
function GetFLVDuration($file,$act){
$duration = false;
switch($act){
case 0:
if (file_exists($file)){
$fp = fopen($file, 'r');
if ($fp) {
$header = fread($fp, 5);
if ($header !== false) {
$is_flv = ($header[0]=='F' && $header[1]=='L' && $header[2]=='V');
$is_flv_video = (hexdec(bin2hex($header[4])) & 0x01);
if ($is_flv && $is_flv_video) {
if (fseek($fp, 0, SEEK_END) == 0) {
$length = ftell($fp);
if ($length !== false) {
if (fseek($fp, -4, SEEK_END) == 0) {
$value = fread($fp,4);
if ($value !== false) {
$taglen = hexdec(bin2hex($value));
if ($length > $taglen) {
if (fseek($fp, $length - $taglen, SEEK_SET) == 0) {
$value = fread($fp, 3);
if ($value !== false) {
$duration = hexdec(bin2hex($value));
$duration = ($duration-$duration%1000)/1000;//值為毫秒,所以除1000算回秒,再捨棄小數
}
}
}
}
}
}
}
}
}
fclose($fp);
}
}
break;
case 1:
if (file_exists($file)){
$handle = fopen($file, "r");
$contents = fread($handle, filesize($file));
fclose($handle);
if (strlen($contents) > 3){
if (substr($contents,0,3) == "FLV"){
$taglen = hexdec(bin2hex(substr($contents,strlen($contents)-3)));
if (strlen($contents) > $taglen){
$duration = hexdec(bin2hex(substr($contents,strlen($contents)-$taglen,3)));
$duration = ($duration-$duration%1000)/1000;//值為毫秒,所以除1000算回秒,再捨棄小數
}
}
}
}
break;
case 2:
require_once("getid3/getid3.php");
$getID3 = new getID3;
$fileData = $getID3->analyze($file);
$duration = $fileData['meta']['onMetaData']['duration'];//meta->onMetaData->lasttimestamp與playtime_seconds的值好像都跟這個一樣
$duration = floor($duration);//getid3是個不錯的東西,只不過,要load它的php進來,若是一個模組mod就好了
//id3抓到的時間是以秒計長度,所以會有小數點,但基於資料庫中的欄位是int屬性,所以就用floor捨棄小數了
break;
}
return $duration;
}

然後,回到前面的49x或5xx行,在「$log->append("start background conversion", 4);」的下一行加上以下的程式
//取得flv的時間
$flvduration=GetFLVDuration($flv_file,2);
if($flvduration==false) $flvduration=0;
//end

所以,$flvduration就是最後經function後的回應值,接著請把下一行的「$dbconn -> easyInput("media", array("media_conversion_info" => "flv", "media_extention" => $fileFormat, "media_id = '".$mid."'");」修改為「$dbconn -> easyInput("media", array("media_conversion_info" => "flv", "media_extention" => $fileFormat, "media_duration" => $flvduration), "media_id = '".$mid."'");」
(另外,有照之前我做的bit_rate與fps的,可以改成「$dbconn -> easyInput("media", array("media_conversion_info" => "flv", "media_extention" => $fileFormat, "media_rate" => "flv", "media_fps" => "flv", "media_duration" => $flvduration), "media_id = '".$mid."'");」)

這是我從google中查得的相關針對flv的媒體資訊,以上的三個方法,在基本的做法上,只是去取得檔案的tag欄位,從這一些欄位分析出我要的東西。像duration就是這文章的主題-時間長度。
在case 0和1中,這二個方式其實是差不多的分析方式,事實上應該使用case 1的就可以了,但經我google一些國外論壇發現有人針對case 1的方式說明了一些bug,所以才有了case 0那種多層式的判斷結構,但事實上,經自己反覆測試之後發現,其實case 1的那個bug不太容易碰到,而且像case 0的判斷方式,反而會多浪費一些不必要的偵測時間。所以,個人認為應該case 1的使用就足夠了。

case 2是網路上常被使用的一個套件(package)或掛件(plugin),運用由http://getid3.sourceforge.net/所開發的getID3的套件來取得多媒體資料結構上的tag。目前我所用的版本是上述網頁的Latest 1.x beta version: 1.7.8-b3。輕鬆、方便又好用,果然是俗又大碗的東東。但唯一讓我不認可的,是為什麼它不進化成php或apache的模組(mod),要不然這一些php的檔案,事實上我認為蠻佔空間的…網路上是有人將特別針對某種檔案的get拿出來當一個function用啦,但osTube搞不好以後還會再有什麼奇怪的變動,所以,我個人是認為留著好配合以後的增進會比較好。

在case 2中還有很多屬性可以取得,想要玩的朋友可以找個php來print_r($fileData),就會看到結構,可以針對你自己想要東西再做增益。

-------又是分隔線--------

好啦,flv取得時間就在這裡簡單的結束了,個人很感謝網路上的高手,雖然我無法貼出出處(因為網頁關閉了),但個人很佩服。
本以為自己得花上一些時間抓這一些東西,但,本藉著「懶」為最高指導原則,而且又有那麼多方便的套件,所以,能用就用唄。
(花最多的時間是在想程式的運作,看看高手們是怎麼寫的)

以上的function我是把三種方式都貼出,然後在GetFLVDuration的第二個參數值來做切換,若只想用一個的,就把switch case拿掉,然後第二個參數值拿掉應該就ok了。

另外,我個人建議是使用case 0或1的function,因為,id3的解tag方式可能比較有它自己的方式,當檔案不大時看不出來,但檔案約略過了10mb,就會有反應時間過久的問題…

沒有留言: