Skip to content

CHICPRO

  • Life Log
  • Cycling Log
  • Photo Log
    • Portrait
    • Landscape
    • Flower
    • Etc
  • Coding Log
  • Information

[PHP] HTTP와 PHP를 이용한 html5 video 스트리밍 구현

2014-08-26 by 편리

일단 제목이 무척 거창하다. 필요에 의해서 검색을 하다가 발견한 내용인데 html5에서 지원하는 video 태그를 이용해 비디오 스트리밍을 제공할 때 진행바를 움직이면 일부 브라우저에서 작동이 멈추는 오류가 있어 이를 해결하기 위해 작성한 코드라고 한다. 나도 마침 스트리밍 기능이 필요해서 코드를 사용해봤다.

출처 : Stream videos to HTML5 video container using HTTP & PHP

그런데 나의 경우 위의 코드를 사용했을 때 Header 정보에서 제공하는 Content-Length 정보가 실제 파일 사이즈와 달라 오류가 발생해 동영상 재상이 되지 않는 문제가 있었다. 그래서 Content-Length header 정보를 추가하는 부분의 코드를 약간 수정해서 사용하니 이상없이 동영상이 재생됐다. 수정한 코드는 아래와 같다.

<?php
set_time_limit(0);
include_once('./_common.php');

// Clears the cache and prevent unwanted output
ob_clean();
@ini_set('error_reporting', E_ALL & ~ E_NOTICE);
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 'Off');

// 동영상정보
$sql = " select file from movie_info where mv_id = '$mv_id' ";
$row = sql_fetch($sql);

if(!$row)
    die('동영상정보가 존재하지 않습니다.');


// Stream videos to HTML5 video container using HTTP & PHP
// http://licson.net/post/stream-videos-php/
$file = './data/movie/'.$row['file']; // The media file's location
if(!is_file($file))
    die('파일이 존재하지 않습니다. 사이트 운영자에게 문의해 주십시오.');
$mime = "application/octet-stream"; // The MIME type of the file, this should be replaced with your own.
$size = filesize($file); // The size of the file

// Send the content type header
header('Content-type: ' . $mime);

// Check if it's a HTTP range request
if(isset($_SERVER['HTTP_RANGE'])){
    // Parse the range header to get the byte offset
    $ranges = array_map(
        'intval', // Parse the parts into integer
        explode(
            '-', // The range separator
            substr($_SERVER['HTTP_RANGE'], 6) // Skip the `bytes=` part of the header
        )
    );

    // If the last range param is empty, it means the EOF (End of File)
    if(!$ranges[1]){
        $ranges[1] = $size - 1;
    }

    // Send the appropriate headers
    header('HTTP/1.1 206 Partial Content');
    header('Accept-Ranges: bytes');
    // Content-Length 가 맞지 않는 오류가 발생하여 주석처리 후 아래 코드로 대체
    //header('Content-Length: ' . ($ranges[1] - $ranges[0])); // The size of the range
    header('Content-Length: ' . $size);

    // Send the ranges we offered
    header(
        sprintf(
            'Content-Range: bytes %d-%d/%d', // The header format
            $ranges[0], // The start range
            $ranges[1], // The end range
            $size // Total size of the file
        )
    );

    // It's time to output the file
    $f = fopen($file, 'rb'); // Open the file in binary mode
    $chunkSize = 8192; // The size of each chunk to output

    // Seek to the requested start range
    fseek($f, $ranges[0]);

    // Start outputting the data
    while(true){
        // Check if we have outputted all the data requested
        if(ftell($f) >= $ranges[1]){
            break;
        }

        // Output the data
        echo fread($f, $chunkSize);

        // Flush the buffer immediately
        @ob_flush();
        flush();
    }
}
else {
    // It's not a range request, output the file anyway
    header('Content-Length: ' . $size);

    // Read the file
    @readfile($file);

    // and flush the buffer
    @ob_flush();
    flush();
}
?>

위 코드는 서버에 저장된 파일을 스트리밍해주는 코드일 뿐이며 브라우저에서 동영상을 보여주기 위해서는 아래와 같은 코드를 사용해서 페이지를 작성해줘야 한다.

<video src="http://example.com/movie.php?mv_id=1234" width="720" height="480" controls="controls" preload="none"></video>

이렇게 했을 경우 동영상 파일의 직접적인 URL을 노출하지 않고도 동영상을 사용자에게 보여줄 수 있다. 추가로 MediaElement.js 를 사용하면 좀 더 쉽게 동영상 보기 화면을 만들 수가 있으니 참고하기 바란다.

Post navigation

Previous Post:

샤오미 10400mAh 보조 배터리 구입

Next Post:

내비게이션 업데이트

2 Commments

  1. Kim says:
    2021-02-22 at 14:54

    오류가 난다고 했던 사이즈 부분에서 헤더를 보면 HTTP/1.1 206 Partial Content로 되어있고..
    아이폰이나 일부 기기 또는 브라우져에서 통째로 받지 않고 일정구간을 호출하여 받는 부분이 있는데, 이런 경우에 사이즈를 파일 사이즈로 대체하게되면 실제로 전송되는 사이즈와 맞지 않아 오류가 발생하는 이슈가 있어서.. 요청한 구간의 크기를 헤더로 셋팅해야하는데.. 문제 없던가요?

    Reply
    1. 편리 says:
      2021-02-22 at 15:27

      안녕하세요.
      2014년도 포스트로 그 당시에는 아이폰을 사용하지 않아서 테스트 자체를 하지 못했습니다.
      최신의 브라우저에서는 오류가 발생할 수도 있을 것 같습니다. 해당 코드는 더 이상 사용하지 않고 있기 때문에 더 이상의 유지보수는 불가능한 점 양해바랍니다.

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent Posts

  • SK 세븐모바일 유심 셀프교체
  • php 배열 연산에서 + 와 array_merge 의 차이
  • pcntl_fork 를 이용한 다중 프로세스 실행
  • 아이폰 단축어를 이용하여 주중 공휴일엔 알람 울리지 않게 하기
  • 구글 캘린더 전체일정 재동기화
  • OpenLiteSpeed 웹서버에 HTTP 인증 적용
  • OpenLiteSpeed 웹어드민 도메인 연결
  • WireGuard를 이용한 VPN 환경 구축
  • Ubuntu 22.04 서버에 OpenLiteSpeed 웹서버 세팅
  • 맥 vim 세팅

Recent Comments

  • 편리 on 업무관리용 그누보드 게시판 스킨
  • 임종섭 on 업무관리용 그누보드 게시판 스킨
  • 캐논 5D 펌웨어 | Dslr 펌웨어 업그레이드 방법 82 개의 베스트 답변 on 캐논 EOS 30D 펌웨어 Ver 1.0.6 , EOS 5D 펌웨어 Ver 1.1.1
  • Top 5 캐논 5D 펌웨어 Top 89 Best Answers on 캐논 EOS 30D 펌웨어 Ver 1.0.6 , EOS 5D 펌웨어 Ver 1.1.1
  • 편리 on 워드프레스 애니메이션 gif 파일을 mp4로 변환하여 출력하기
  • 임팀장 on 워드프레스 애니메이션 gif 파일을 mp4로 변환하여 출력하기
  • 편리 on Notepad++ NppFTP 플러그인 수동 설치
  • paul-j on Notepad++ NppFTP 플러그인 수동 설치
  • YS on Windows 10 iCloud 사진 저장 폴더 변경
  • 편리 on Docker를 이용한 Centos7 + httpd + php 5.4 개발환경 구축

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org
© 2025 CHICPRO | Built using WordPress and SuperbThemes