Где узкое место в вещании mjpeg? - PullRequest
1 голос
/ 12 ноября 2011

Я транслирую mjpeg с PHP так же, как это

<?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 работает еще хуже.

Какая это может быть проблема?

Ответы [ 2 ]

1 голос
/ 21 июня 2012

Я не уверен, что этот вопрос все еще актуален, но даже если это не так, прямого ответа нет.

Я предполагаю, что вы получаете сообщение об ошибке «изображение повреждено или усечено». Мой код почти идентичен, и я столкнулся с той же проблемой при использовании usleep (..).

Основной причиной является размещение usleep (..) - его следует вызывать до print ($ border), а не после. Когда вы размещаете его после печати, браузер обнаружит, что что-то не так, так как он ожидает изображение непосредственно после границы раздела. В этом коде сразу после Границы используется usleep (..), который удерживает поток в течение 100 мс, и из-за этого браузера считает, что что-то не так.

Изменить этот код:

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

На этот:

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

И все будет работать нормально.

1 голос
/ 15 ноября 2011

На основании только предоставленной информации:

10 кадров в секунду могут быть немного агрессивными для mjpeg, если размер / разрешение кадра больше.Помните, что это не MPEG, где статические части кадра не отправляются.Здесь весь кадр / изображение отправляется каждый раз.Сначала я бы попытался снизить частоту кадров примерно до 5. Если проблема улучшается, то вы знаете, что проблема заключается в скорости передачи данных, где-то / как-то.Возможно, вы сможете улучшить вашу проблему со скоростью 10 кадров в секунду, если ваш код сначала буферизует некоторые кадры, а затем читает из буфера.Таким образом, если кадр медленно показывает ваш код или браузер, не задохнитесь.Я думаю, что вам также нужно ограничить время, в течение которого ваш код будет ожидать появления изображения, прежде чем сдаться и продолжить переход к следующему изображению.Надеюсь, это поможет.

...