問題描述
我想要一個(gè) PHP 函數(shù),它接收文件的路徑并返回有關(guān)它的信息數(shù)組.PHP文件可以調(diào)用FFmpeg.
I want a PHP function which receives the path to a file and returns an array of information about it. The PHP file can call FFmpeg.
返回的數(shù)據(jù)應(yīng)該類似于
Array(
[mime] => video/ogg
[container] => Ogg
[video] => Theora
[audio] => Vorbis
[duration] => 20.3 // in seconds
)
Array(
[mime] => audio/ogg
[container] => Ogg
[video] =>
[audio] => FLAC
[duration] => 3
)
Array(
[mime] => image/gif
[container] => GIF
[video] => Animated GIF
[audio] =>
[duration] => 2
)
Array(
[mime] => video/webm
[container] => WebM
[video] => VP8
[audio] => Vorbis
[duration] => 900.7
)
false // not a media file
我從未使用過 FFmpeg 或 PHP 的 shell_exec()
函數(shù),但似乎 FFmpeg 會(huì)以一種相當(dāng)難以解析的格式提供有關(guān)視頻(或音頻文件)的信息.不過,我認(rèn)為這樣的事情是可能的.
I've never worked with FFmpeg or with PHP's shell_exec()
function, but it seems that FFmpeg will give information about videos (or audio files) in a fairly hard-to-parse format. I assume that something like this is possible, though.
推薦答案
FFmpeg 幾乎可以做您想做的一切,但您說得對(duì),它幾乎無法解析格式.如果您在基于 UNIX 的系統(tǒng)上使用操作系統(tǒng)和 FFmpeg 的功能進(jìn)行解析,而不是讓 PHP 嘗試?yán)斫廨敵觯敲磳?shí)際上會(huì)更快.幾個(gè)月前,我出于類似目的開發(fā)了以下 shell 命令.
FFmpeg can do just about everything you want, but you're correct that it's in a nearly impossible to parse format. It's actually quicker if you're on a UNIX-based system to use the Operating System and the features of FFmpeg to do the parsing rather than have PHP try to understand the output. I developed the following shell command several months ago for a similar purpose.
fulltime=`ffmpeg -i MOVIE.AVI 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//`;hour=`echo $fulltime | cut -d ':' -f 1`;minute=`echo $fulltime | cut -d ':' -f 2`;second=`echo $fulltime | cut -d ':' -f 3 | cut -d '.' -f 1`;echo `expr 3600 * $hour + 60 * $minute + $second`
管道 (|
) 告訴 UNIX 將前一個(gè)命令的輸出作為輸入傳遞給下一個(gè)命令.分號(hào) (;
) 告訴 UNIX 開始一個(gè)新命令.UNIX shell 還允許動(dòng)態(tài)創(chuàng)建變量.要?jiǎng)?chuàng)建變量,您只需說var=value
.要調(diào)用此變量,您必須使用美元符號(hào),例如 $var
.
The pipe (|
) tells UNIX to pass the output of the previous command as the input to the next command. The semi-colon (;
) tells UNIX to begin a new command. The UNIX shell also allows for on-the-fly variable creation. To create a variable you just say var=value
. To recall this variable you must use a dollar-sign, such as $var
.
我的命令基本上采用 ffmpeg -i MOVIE.AVI 2>&1 | 的輸出grep '持續(xù)時(shí)間' |剪切 -d ' ' -f 4 |sed s/,//
并將其存儲(chǔ)為 fulltime
.此命令進(jìn)一步細(xì)分:
My command essentially takes the output of ffmpeg -i MOVIE.AVI 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//
and stores it as fulltime
. This command is further broken down:
ffmpeg -i MOVIE.AVI 2>&1
表示顯示 MOVIE.AVI 的信息(-i
).2>&1
我相信將輸出重定向到管道而不是屏幕(這是很久以前做的,所以我不清楚)
ffmpeg -i MOVIE.AVI 2>&1
means to display info (-i
) for MOVIE.AVI. The 2>&1
I believe redirected the output to a pipe rather than to the screen (made this forever ago, so I'm not clear on that)
grep 'Duration'
將獲取輸入(這是 ffmpeg -i MOVIE.AVI 2>&1
的輸出),找到單詞 'Duration', 并僅輸出包含該單詞的行.
grep 'Duration'
will take the input (which was the output of ffmpeg -i MOVIE.AVI 2>&1
), find the word 'Duration', and output only the line that contained that word.
cut -d ' ' -f 4
將獲取輸入(前一條語句的輸出),在每個(gè)空格處將其拆分(' '
),然后只輸出其中的第四個(gè).這是因?yàn)?FFmpeg 的輸出看起來像:
cut -d ' ' -f 4
will take the input (the output of the previous statement), split it up at every space (' '
), and output only the fourth of these. This is because the output of FFmpeg looks something like:
MOVIE.AVI
video encoder, yada yada
audio encoder, yada yada
bitrates and stuff
Duration: hh:mm:ss fulltime: 00:30:00.1
換句話說,包含持續(xù)時(shí)間"的行的第四個(gè)部分"是實(shí)際持續(xù)時(shí)間……以小時(shí)、分鐘和秒為單位(保留 1 個(gè)小數(shù)位).
In other words, the fourth "section" of the line containing "Duration" is the actual duration... In hours, minutes, and seconds (with 1 decimal place).
sed s/,//
表示將 ',' 替換為空.這可能是有充分理由的.
sed s/,//
means to replace ',' with nothing. There was probably a good reason for this.
在此之后,我創(chuàng)建了三個(gè)變量 hour
、minute
和 second
:
After this I created the three variables hour
, minute
, and second
:
hour=`echo $fulltime | cut -d ':' -f 1`;
minute=`echo $fulltime | cut -d ':' -f 2`;
second=`echo $fulltime | cut -d ':' -f 3 | cut -d '.' -f 1`;
請(qǐng)注意,我正在為 echo $fulltime | 的輸出設(shè)置小時(shí).cut -d ':' -f 1
.如果我要在每個(gè)冒號(hào)(:
)
Notice that I'm setting hour to the output of echo $fulltime | cut -d ':' -f 1
. Grabbing the first portion if I were to split the time at every colon (:
)
我對(duì)分鐘做了類似的處理,然后我對(duì)秒做同樣的處理,只是在最后去掉了任何小數(shù)點(diǎn).如果您在 shell 中工作,則必須刪除這個(gè)小數(shù)點(diǎn),因?yàn)?expr
命令(我曾經(jīng)用它從小時(shí)、分鐘和秒計(jì)算秒)只執(zhí)行整數(shù)數(shù)學(xué)運(yùn)算.如果您希望在持續(xù)時(shí)間內(nèi)保留小數(shù),此時(shí)您必須將小時(shí)、分鐘和秒返回給 PHP 并在那里進(jìn)行解析.將以上內(nèi)容替換為:
I do similar with minutes, then I do the same with seconds only I chop off any decimal at the end. This decimal has to be removed if you're working in shell since the expr
command (which I used to calculate seconds from hours, minutes, and seconds) only performs integer math. If you wish to keep the decimal for duration, you will at this point have to return the hours, minutes, and seconds to PHP and do the parsing there. This would be most easily done by replacing the above with:
echo $fulltime
這將在您調(diào)用 shell_exec()
后向 PHP 返回一個(gè)字符串,例如00:30:00.1",然后您可以使用 explode(':',$string)
.
This will return a string such as "00:30:00.1" to PHP after you have called shell_exec()
, which you can then easily parse using explode(':',$string)
.
繼續(xù)直接從 shell 獲取秒數(shù):
To continue with getting the seconds directly from shell:
在得到小時(shí)、分鐘和秒后,出現(xiàn)了神奇的一行:
After getting the hours, minutes, and seconds came the magical line:
echo `expr 3600 * $hour + 60 * $minute + $second`
expr
命令表示執(zhí)行數(shù)學(xué)表達(dá)式.不幸的是,它相當(dāng)愚蠢.首先,需要對(duì)特殊字符進(jìn)行轉(zhuǎn)義(*
在 UNIX 中是通配符,因此必須使用 *
表示乘法).接下來,它只執(zhí)行整數(shù)數(shù)學(xué).如您所見,將小時(shí)乘以 3600,分鐘乘以 60,然后將它們加在一起是相當(dāng)容易的.
The expr
command says to perform a mathematical expression. Unfortunately it's rather stupid. First, special characters need to be escaped (*
is a wildcard in UNIX, so you have to use *
to mean multiply). Next, it only performs integer math. It was fairly easy, as you can see, to multiply hours by 3600, minutes by 60, and add them all together.
整個(gè)龐大命令的輸出將只是一個(gè)數(shù)字.視頻持續(xù)的秒數(shù).它應(yīng)該適用于所有視頻格式.
The output of this entire, massive command, will just be a single number. The number of seconds that the video lasts. It should work for all video formats.
請(qǐng)注意,這只是持續(xù)時(shí)間.至于視頻編碼器和音頻編碼器,您可能希望使用類似的方法,最后減去數(shù)學(xué)運(yùn)算.一個(gè)通用的解決方案是:
Mind you this is just duration. As for video encoder and audio encoder you would want to use similar methods, minus the math at the end. A generic solution would be:
ffmpeg -i MOVIE.AVI 2>&1 | grep 'Something unique to the line you want' | cut -d ' ' -f <the "section" you want>
這個(gè)輸出可以繼續(xù)在 shell 中解析(就像我在上面所做的那樣)或者它可以傳遞給 PHP.
The output of this can either continue to be parsed in shell (as I did above with the time) or it can be passed to PHP.
這篇關(guān)于查詢音頻/視頻文件的信息的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!