30 апр. 2012 г.

Автоматическая конвертация видео для стримминга

Задача: Автоматически конвертировать видео для стримминга через nginx
Допустим у нас на сервере есть папка куда будет поступать видео файлы, обычные которые вы скачиваете через торрент. Нам необходимо автоматически конвертировать эти файлы для пригодного формата.

Теперь приступим. На сервере должна быть установлена ffmpeg с H264 енкодером. В этом вам поможет гугл.

Есть замечательный инструмент ffprobe, который может извлекать всю необходимую информацию из медиа файла, и выводить в красивом(json, xml) формате. Нам надо пройтись по папке и найти все видео файлы, и записать в json файл.

#!/bin/bash
INPUT_DIR="/home/user1/to_convert/"
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
rm videofiles.json
count=$(find $INPUT_DIR -name "*.avi" | wc -l)
echo "[" >> 'videofiles.json'
for i in $(find $INPUT_DIR -name "*.avi")
do
    ffprobe -v quiet -print_format json -show_format $i >> 'videofiles.json'
    if [ $count -ne 1 ];then
        echo "," >> 'videofiles.json'
        count=$(( $count - 1 ))
        echo $count
    fi
done;
echo "]" >> 'videofiles.json'
IFS=$SAVEIFS

Следующий шаг, сделать готовый bash скрипт из json файла. 2-й этап возьмет на себя питон скрипт. Почему питон? Потому что есть готовый парсер для json, да и времени сэкономит.

Вот скрипт:
#!/usr/bin/python

import json
import os
import sys
import codecs

def ffmpegReady(filename, destFile1, destFile2, bit_rate):
 bitrate=int(bit_rate)
 bitrate1=0
 bitrate2=0
 if 1500 < bitrate:
  bitrate1=str(int(bitrate*0.8))
  bitrate2=str(int(bitrate*0.25))
 elif bitrate <1500:
  bitrate1=str(int(bitrate*0.9))
  bitrate2=str(int(bitrate*0.33))

 ffmpeg_command = "ffmpeg -i \""+filename +"\" -vcodec libx264 -acodec libfaac -b:v "+bitrate1+"k -threads 0 -r 24 -g 24 \""+destFile1+".mp4"+"\"\n"
 ffmpeg_command = ffmpeg_command + "qtfaststart \""+destFile1+".mp4\" \""+destFile1[:-4]+".mp4\"\n"
 ffmpeg_command = ffmpeg_command + "rm -f \""+ destFile1+".mp4\"\n"
 ffmpeg_command = ffmpeg_command + "ffmpeg -i \""+filename +"\" -s 480x360 -vcodec libx264 -acodec libfaac -b:v "+bitrate2+"k -threads 0 -r 24 -g 24 \""+destFile2+".mp4"+"\"\n"
 ffmpeg_command = ffmpeg_command + "qtfaststart \""+destFile2+".mp4\" \""+destFile2[:-4]+".mp4\"\n"
 ffmpeg_command = ffmpeg_command + "rm -f \"" + destFile2 + ".mp4\"\n"
 ffmpeg_command = ffmpeg_command + "rm -f \""+ filename+"\"\n"

 return ffmpeg_command

здесь я показал часть которая генерирует команду. Как видите у меня 2 выходных файла. Один с нормальным, другой с низким качеством. Также используется утилита qtfaststart для перемещения мета информации в начало файла. Это поможет нам уменьшить время запуска проигрывания.

В конце у нас получится готовый bash скрипт для запуска.

Теперь соединим все в один файл:
#!/bin/bash

DATE=`/bin/date`
qt=$(ps aux | grep 'qtfaststart' | grep -v grep | wc -l | tr -s "\n")
ff_p=$(ps aux | grep 'ffmpeg' | grep -v grep | wc -l | tr -s "\n")

if [ -e convert_process ]
then 
 echo "$DATE    process not finished" >> log.txt
else
 if [[ $qt > 0 || $ff_p > 0 ]]
 then
  echo "ffmpeg or qtfaststart already running, try later" >> log.txt
 else
  touch convert_process
  echo "$DATE    Scanning ..." >> log.txt
  ./convert.sh 
  echo "$DATE    Parsing ..."  >> log.txt
  ./parsejson.py
  echo "$DATE    Starting ..."  >> log.txt
  screen -d -m ./runnable.sh
  echo "$DATE    Finished." >> log.txt
  rm -f convert_process
 fi

fi
Все. Скрипт можно поставить в крон задачи. Статья не претендует на how to. Это просто один из тысячи методов. Также приветсвуется подсказки и пожелания.

P.S. код на гитхабе https://github.com/samlabs821/Server-side/