2011-11-12 66 views
1

我流MJPEG與PHP就這樣mjpeg廣播的瓶頸在哪裏?

<?php 
//example /cli/watch.php?i=0&j=200 

function get_one_jpeg($i) { 
    $path = "img"; 
    //$f = fopen("$path/$i.jpg", "rb"); 
    return file_get_contents("$path/$i.jpg"); 
} 
ini_set('display_errors', 1); 
# Used to separate multipart 
$boundary = "my_mjpeg"; 

# We start with the standard headers. PHP allows us this much 
//header("Connection: close"); 
header("Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0"); 
header("Cache-Control: private"); 
header("Pragma: no-cache"); 
header("Expires: -1"); 
header("Content-type: multipart/x-mixed-replace; boundary=$boundary"); 

# From here out, we no longer expect to be able to use the header() function 
print "--$boundary\n"; 

# Set this so PHP doesn't timeout during a long stream 
set_time_limit(0); 

# Disable Apache and PHP's compression of output to the client 
@apache_setenv('no-gzip', 1); 
@ini_set('zlib.output_compression', 0); 

# Set implicit flush, and flush all current buffers 
@ini_set('implicit_flush', 1); 
for ($i = 0; $i < ob_get_level(); $i++) 
    ob_end_flush(); 
ob_implicit_flush(1); 

# The loop, producing one jpeg frame per iteration 
$i = $_GET['i']; 
$j = $_GET['j']; 

while ($i <= $j) { 
    # Per-image header, note the two new-lines 
    print "Content-type: image/jpeg\n\n"; 

    # Your function to get one jpeg image 
    print get_one_jpeg($i); 

    # The separator 
    print "--$boundary\n"; 

    # Sleeping for 0.1 seconds for 10 frames in second 
    usleep(100000); 

    $i++; 
} 
?> 

但如果我設置了大範圍的圖像,例如,從0到300,在不確定的時間瀏覽器只是停止顯示。

這不是一個特定的框架或時刻,並且顯示在不同的瀏覽器中,所以我認爲它的注意點是Apache。

我在Apache 2.2.9和2.2.21下試過了,得到了同樣的結果。在IIS Express下工作更糟糕。

它可能是什麼問題?

+0

包含文件時請不要直接使用'$ _GET'變量,否則可能會導致一些嚴重的安全問題! – gnur

+0

感謝您的評論,我使用這種方式只是爲了測試 – Saito

回答

1

僅基於給定的信息:每秒

10幀可以是用於MJPEG一點aggresive如果幀尺寸/分辨率更大。請記住,這不是mpeg,靜態框架的部分不會被髮送。這裏每次發送整個幀/圖像。我會首先嚐試降低幀速率到5左右。如果問題改善,那麼你知道問題是數據速率,在某處/以某種方式。如果您的代碼先緩衝了一些幀然後從緩衝區中讀取,那麼您可能能夠以10 fps的速度改善問題。這樣,如果一個框架顯示緩慢,你的代碼或瀏覽器不會窒息。我認爲在放棄和繼續下一張圖像之前,您還需要限制代碼等待圖像顯示的時間。希望這可以幫助。

1

我不確定這個問題是否仍然有效,但即使不是,也沒有直接的答案。

我假設你得到「圖像損壞或截斷」錯誤。我的代碼幾乎完全相同,使用usleep(..)時遇到同樣的問題。

根本原因是睡眠(..)放置 - 它應該在打印之前調用($邊界),而不是之後。在打印後放置的時候,因爲在邊界部分之後直接期待圖像所以瀏覽器會發生什麼不對的東西。在這個代碼中,在邊界處於睡眠狀態(..)之後立即將流保持爲100ms,並且因爲那個瀏覽器認爲有什麼錯誤。

更改此代碼:

print "--$boundary\n"; 
usleep(100000); 

這一個:

usleep(100000); 
print "--$boundary\n"; 

,一切都會正常工作。