11/08/2018, 20:39

Chống download file video trên web cơ bản bằng HLS, kết hợp với Laravel

Xin chào mọi người :D Trong bài viết này mình sẽ trình bày một cách cơ bản để ứng dụng kỹ thuật Http Live Streaming (HLS) để play video trên web, đồng thời có thể hạn chế được việc download video qua cách này. Bài viết này sử dụng kết hợp Laravel trong việc xây dựng ứng dụng web. Nào cùng bắt đầu ...

Xin chào mọi người :D
Trong bài viết này mình sẽ trình bày một cách cơ bản để ứng dụng kỹ thuật Http Live Streaming (HLS) để play video trên web, đồng thời có thể hạn chế được việc download video qua cách này. Bài viết này sử dụng kết hợp Laravel trong việc xây dựng ứng dụng web. Nào cùng bắt đầu :D

HLS là viết tắt cho Http Live Streaming, một kỹ thuật truyền phát media dựa trên giao thức HTTP do Apple phát triển. Khác với kỹ thuật phát video thông thường, HLS chia tệp tin video (hoặc một luồng live) thành một loạt các file nhỏ. Sau đó, player từ phía trình duyệt sẽ request và phát các file nhỏ liên tiếp nhau, tạo thành một video hoàn chỉnh. HLS hỗ trợ phát stream dưới nhiều dạng chất lượng khác nhau, và player sẽ tự động lựa chọn tốc độ cho phù hợp với băng thông mạng. Thuật ngữ này được gọi là Adaptive Streaming (Stream thích nghi với điều kiện).

alt text

Hình đơn giản mô tả về cách thức HLS vận hành.

Nhờ việc phát video dựa trên stream từng file nhỏ về phía player, việc download video trở nên khó khăn hơn. Nếu view source thì cũng chỉ thấy được file chỉ mục (là file index các file riêng lẻ sẽ được phát về client). Thử nghiệm cơ bản thấy các trình duyệt như Cốc cốc hoặc các tool download bắt link đều không thể tải được. Còn nếu áp dụng kỹ thuật cao hơn thì mình cũng không chắc :D :D

Để sử dụng được HLS, chúng ta cần sử dụng thư viện ffmpeg. Môi trường cài đặt của mình ở đây là Ubuntu 16.04. Cài đặt ffmpeg ở đây sẽ hơi phức tạp hơn bình thường chút, vì chúng ta sẽ cần compile source của ffmpeg cùng với các thư viện mã hóa - giải mã video / audio như x264, aac ... Tuy nhiên rất may là mình đã kiếm được một file bash trên mạng làm giúp tất cả chúng ta điều này. Bạn chạy file bash sau nhé:

#!/bin/bash
# Bash script to install latest version of ffmpeg and its dependencies on Ubuntu 12.04 or 14.04
# Inspired from https://gist.github.com/faleev/3435377
# Remove any existing packages:
sudo apt-get -y remove ffmpeg x264 libav-tools libvpx-dev libx264-dev
# Get the dependencies (Ubuntu Server or headless users):
sudo apt-get update
sudo apt-get -y install build-essential checkinstall git libfaac-dev libgpac-dev
libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev librtmp-dev libtheora-dev
libvorbis-dev pkg-config texi2html yasm zlib1g-dev
# Update nasm
cd
curl -O http://www.nasm.us/pub/nasm/releasebuilds/2.13.01/nasm-2.13.01.tar.gz
tar -xvzf nasm-2.13.01.tar.gz
cd nasm-2.13.01
./configure
make
make install
sudo checkinstall --pkgname=nasm --pkgversion="2.13.01" --backup=no
--deldoc=yes --fstrans=no --default
# Install x264
sudo apt-get -y install libx264-dev
cd
git clone --depth 1 git://git.videolan.org/x264
cd x264
./configure --enable-static
make
sudo checkinstall --pkgname=x264 --pkgversion="3:$(./version.sh |
awk -F'[" ]' '/POINT/{print $4"+git"$5}')" --backup=no --deldoc=yes
--fstrans=no --default
# Install AAC audio decoder
cd
wget http://downloads.sourceforge.net/opencore-amr/fdk-aac-0.1.0.tar.gz
tar xzvf fdk-aac-0.1.0.tar.gz
cd fdk-aac-0.1.0
./configure
make
sudo checkinstall --pkgname=fdk-aac --pkgversion="0.1.0" --backup=no
--deldoc=yes --fstrans=no --default
# Install VP8 video encoder and decoder.
cd
git clone --depth 1 https://chromium.googlesource.com/webm/libvpx
cd libvpx
./configure
make
sudo checkinstall --pkgname=libvpx --pkgversion="1:$(date +%Y%m%d%H%M)-git" --backup=no
--deldoc=yes --fstrans=no --default
# Add lavf support to x264
# This allows x264 to accept just about any input that FFmpeg can handle and is useful if you want to use x264 directly. See a more detailed explanation of what this means.
cd ~/x264
make distclean
./configure --enable-static
make
sudo checkinstall --pkgname=x264 --pkgversion="3:$(./version.sh |
awk -F'[" ]' '/POINT/{print $4"+git"$5}')" --backup=no --deldoc=yes
--fstrans=no --default
# Installing FFmpeg
cd
git clone --depth 1 git://source.ffmpeg.org/ffmpeg
cd ffmpeg
./configure --enable-gpl --enable-libmp3lame --enable-libopencore-amrnb
--enable-libopencore-amrwb --enable-librtmp --enable-libtheora --enable-libvorbis
--enable-libvpx --enable-libx264 --enable-nonfree --enable-version3
make
sudo checkinstall --pkgname=ffmpeg --pkgversion="5:$(date +%Y%m%d%H%M)-git" --backup=no
--deldoc=yes --fstrans=no --default
view raw install_ffmpeg_ubuntu.sh hosted with ❤ by GitHub

Sau khi bạn chạy file bash thành công, ta tiếp tục tiến hành cài đặt package để xử lý HLS trên Laravel:

composer require pbmedia/laravel-ffmpeg

Link github của package: https://github.com/pascalbaljetmedia/laravel-ffmpeg

Các bạn sau khi publish file config của package:

php artisan vendor:publish --provider="PbmediaLaravelFFMpegFFMpegServiceProvider"

có thể chạy lệnh:
which ffprobe và which ffmpeg

rồi điền kết quả tương ứng vào file laravel-ffmpeg trong thư mục config cho chuẩn nhé.

Các bạn chú ý là version 2.0 của package chỉ hỗ trợ laravel 5.6, với Laravel bản thấp hơn bạn vui lòng cài đặt bản 1.3.

Kế tiếp ta tiến hành xử lý video. Giả sử bạn đã có file sample.mp4 lưu trong thư mục public của laravel chẳng hạn. Vậy đoạn code để tách file đó thành dạng HLS sẽ như thế này:

        $lowBitrate = (new X264)->setKiloBitrate(250);
        $midBitrate = (new X264)->setKiloBitrate(500);
        $highBitrate = (new X264)->setKiloBitrate(1000);

        FFMpegFacade::fromDisk('videos')
            ->open('sample.mp4')
            ->exportForHLS()
            ->setSegmentLength(10) // optional
            ->addFormat($lowBitrate)
            ->addFormat($midBitrate)
            ->addFormat($highBitrate)
            ->save('sample_out.m3u8');

Có một cái chú ý cũng nho nhỏ là fromDisk ở đây nó đọc từ filesystems trong config Laravel ra nha. Như ở trên mình đã thêm một cái disk là 'videos' với đường dẫn là public/videos vào trong filesystems

Chạy đoạn code đó xong, bạn sẽ ra kết quả như hình:

alt text

Vậy là chúng ta đã thành công. File m3u8 chính là file chứa index tới các file con, còn các file đuôi ts chính là các file con được tách ra để play (Hình mình dùng video hơi nhẹ nên nó không có nhiều file .ts, nếu file nặng hơn thì sẽ khá nhiều, kiểu như thế này)
alt text

Ta đã xong bước tạo các thành phần cần thiết cho HLS. Giờ đến bước cuối, phát trên trình duyệt.

Quá trình mình tìm hiểu HLS thì do nó được Apple phát triển nên các trình duyệt hỗ trợ nhau khá là lung tung. Thật may là ta đã có lời giải cho bài toán này bằng HLS.js (Cái gì trên đời này lắp đuôi js vào là cũng có thì phải). Thư viện này giúp chúng ta phát HLS một cách khá đơn giản và nhẹ nhàng.

Github: https://github.com/video-dev/hls.js/

Đầu tiên bạn nhúng file js:

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>

Một đoạn code (mình copy luôn từ demo của hls.js :D) :

<video id="video"></video>
<script>
  if(Hls.isSupported()) {
    var video = document.getElementById('video');
    var hls = new Hls();
    hls.loadSource('sample_out.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
  });
 }
 // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
 // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element throught the `src` property.
 // This is using the built-in support of the plain video element, without using hls.js.
  else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = 'sample_out.m3u8';
    video.addEventListener('canplay',function() {
      video.play();
    });

</script>

Bạn chú ý nhớ thay đường dẫn tới file m3u8 bạn vừa tạo được vào đoạn script trên nhé.

Demo hls bạn có thể thấy tại đây: https://video-dev.github.io/hls.js/demo/

Vậy là xong cơ bản về HLS rồi :D. Mình thấy nó khá hữu ích trong việc play media trên web, gọn nhẹ và cũng chống được những thao tác download cơ bản. Cám ơn các bạn đã đọc hết bài viết và mong nó hữu ích với mọi người :D.

Mình có tham khảo bài viết tại:

https://github.com/hoangdh/ghichep-StreamingVideo

0