PHP ve FFMPEG - Sahne akıllı video dönüştürme

3 Cevap php

Ben gerçekleştirmek için bir tuhaf zor bir görev var. Bunun kolay olacağını düşündüm, ama benim tüm çabaları sonuçsuz kalmıştır.

Ben bir tek. Flv formatında (. Mpg,. Wmv,. Mov, vb. Avi) çeşitli biçimlerde bir php komut dosyası yüklenen videoları dönüştürme değilim. Dönüşüm harika çalışıyor ama ne ile sorun yaşıyorum videoları çözünürlüğü olur.

Bu (PHP vars ile) Şu anda koşuyorum komut:

ffmpeg -i $original -ab 96k -b 700k -ar 44100 -s 640x480 -acodec mp3 $converted

$ Özgün ve $ dönüştürüldü hem de bu dosyaların tam yolları içerir. Benim sorunum (ben bunu söylüyorum gibi) kaynak daha küçük olsa bile bu her zaman 640x480 dönüştürür olduğunu. Açıkçası, bu disk alanı ve görüntü indirilen bant genişliği kaybıdır. Ayrıca, bu giriş videoları ben 16:9 video upload eğer bir "ezilmiş" dönüşümle sonuçlanır 04:03 dışında herhangi bir boy oranı olduğu için hesaba katmaz.

Yapmam gereken 3 şey vardır:

  1. Orijinal videonun en boy oranını belirleyin.
  2. Eğer siyah çubuklar ile değil 04:03, ped alt ve üst.
  3. Orijinal ya boyutu büyük veya 4:3 en-boy oranı (640x480 yakın hangisi) orijinal genişlik / yükseklik ilişkin ise 640x480 dönüştürün.

Ben bir kaç videoları ffmpeg -i koşuyoruz, ama ben gelen orijinalin çözünürlüğünü bulmak için tutarlı bir format veya yerini görmüyorum. Bunu anlamaya muktedir değilim kez, ben doğru boyut anlamaya ve boy oranı ile-padttop,-padbottom, vb düzeltmek için doldurma belirtmek için "matematik yapmak" biliyorum

3 Cevap

Bu benim için çalışıyor:

$data = 'ffmpeg output';
$matches = array();

if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/',$data,$matches)
   preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\)/',$data,$matches)

Bu always işe yaramayabilir, ama çoğu benim durumumda yeterince iyiydi zamanlarda çalışır :)

Tamam. Ben tam işlevsel bir çözüm var. Bu aynı şeyi yapmak isteyen bu soruyu bulur herkes içindir. Benim kod çok zarif olmayabilir, ama o işi alır.


Getting FFMPEG's output

Önce kendi içinde bir meydan okuma olduğunu ffmpeg-i den çıktı, almak zorunda kaldı. Üzerinde hegemon cevabı sayesinde my other question, sonunda benim komutun sonunda 2>&1 ile çalışma almak başardı. Ve bu soruya Evert cevabı için teşekkürler, ben preg_match, orijinal dosyanın yükseklik ve genişliğini bulmak için birlikte çıkışını ayrıştırmak başardı.

function get_vid_dim($file)
{
    $command = '/usr/bin/ffmpeg -i ' . escapeshellarg($file) . ' 2>&1';
    $dimensions = array();
    exec($command,$output,$status);
    if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/',implode('\n',$output),$matches))
    {
        preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\)/',implode('\n',$output),$matches);
    }
    if(!empty($matches['width']) && !empty($matches['height']))
    {
        $dimensions['width'] = $matches['width'];
        $dimensions['height'] = $matches['height'];
    }
    return $dimensions;
}

Determining the best dimensions

Ben dönüşüm için kullanılacak en iyi boyutlarını belirlemek için bu fonksiyonu yazdım. Bu orijinalin boyutları, hedef boyutları, ve (onun genişlik / yükseklik belirlenir) hedef boy oranına dönüşüm zorlamak için olsun veya olmasın alır. Hedef boyutları her zaman bu işlev dönebilir büyük sonuç olacaktır.

function get_dimensions($original_width,$original_height,$target_width,$target_height,$force_aspect = true)
{
    // Array to be returned by this function
    $target = array();
    // Target aspect ratio (width / height)
    $aspect = $target_width / $target_height;
    // Target reciprocal aspect ratio (height / width)
    $raspect = $target_height / $target_width;

    if($original_width/$original_height !== $aspect)
    {
        // Aspect ratio is different
        if($original_width/$original_height > $aspect)
        {
            // Width is the greater of the two dimensions relative to the target dimensions
            if($original_width < $target_width)
            {
                // Original video is smaller.  Scale down dimensions for conversion
                $target_width = $original_width;
                $target_height = round($raspect * $target_width);
            }
            // Calculate height from width
            $original_height = round($original_height / $original_width * $target_width);
            $original_width = $target_width;
            if($force_aspect)
            {
                // Pad top and bottom
                $dif = round(($target_height - $original_height) / 2);
                $target['padtop'] = $dif;
                $target['padbottom'] = $dif;
            }
        }
        else
        {
            // Height is the greater of the two dimensions relative to the target dimensions
            if($original_height < $target_height)
            {
                // Original video is smaller.  Scale down dimensions for conversion
                $target_height = $original_height;
                $target_width = round($aspect * $target_height);
            }
            //Calculate width from height
            $original_width = round($original_width / $original_height * $target_height);
            $original_height = $target_height;
            if($force_aspect)
            {
                // Pad left and right
                $dif = round(($target_width - $original_width) / 2);
                $target['padleft'] = $dif;
                $target['padright'] = $dif;
            }
        }
    }
    else
    {
        // The aspect ratio is the same
        if($original_width !== $target_width)
        {
            if($original_width < $target_width)
            {
                // The original video is smaller.  Use its resolution for conversion
                $target_width = $original_width;
                $target_height = $original_height;
            }
            else
            {
                // The original video is larger,  Use the target dimensions for conversion
                $original_width = $target_width;
                $original_height = $target_height;
            }
        }
    }
    if($force_aspect)
    {
        // Use the target_ vars because they contain dimensions relative to the target aspect ratio
        $target['width'] = $target_width;
        $target['height'] = $target_height;
    }
    else
    {
        // Use the original_ vars because they contain dimensions relative to the original's aspect ratio
        $target['width'] = $original_width;
        $target['height'] = $original_height;
    }
    return $target;
}

Usage

Burada şeyleri daha net yapmak için get_dimensions() elde edecek ne bir kaç örnek:

get_dimensions(480,360,640,480,true);
-returns: Array([width] => 480, [height] => 360)

get_dimensions(480,182,640,480,true);
-returns: Array([padtop] => 89, [padbottom] => 89, [width] => 480, [height] => 360)

get_dimensions(480,182,640,480,false);
-returns: Array([width] => 480, [height] => 182)

get_dimensions(640,480,480,182,true);
-returns: Array([padleft] => 119, [padright] => 119, [width] => 480, [height] => 182)

get_dimensions(720,480,640,480,true);
-returns: Array([padtop] => 27, [padbottom] => 27, [width] => 640, [height] => 480)

get_dimensions(720,480,640,480,false);
-returns: Array([width] => 640, [height] => 427)

The Finished Product

Şimdi, hep birlikte koymak için:

$src = '/var/videos/originals/original.mpg';
$original = get_vid_dim($src);
if(!empty($original['width']) && !empty($original['height']))
{
    $target = get_dimensions($original['width'],$original['height'],640,480,true);
    $command = '/usr/bin/ffmpeg -i ' . $src . ' -ab 96k -b 700k -ar 44100 -s ' . $target['width'] . 'x' . $target['height'];
    $command .= (!empty($target['padtop']) ? ' -padtop ' . $target['padtop'] : '');
    $command .= (!empty($target['padbottom']) ? ' -padbottom ' . $target['padbottom'] : '');
    $command .= (!empty($target['padleft']) ? ' -padleft ' . $target['padleft'] : '');
    $command .= (!empty($target['padright']) ? ' -padright ' . $target['padright'] : '');
    $command .= ' -acodec mp3 /var/videos/converted/target.flv 2>&1';

    exec($command,$output,$status);

    if($status == 0)
    {
        // Success
        echo 'Woohoo!';
    }
    else
    {
        // Error.  $output has the details
        echo '<pre>',join('\n',$output),'</pre>';
    }
}

PHP ile aşina değilim, ama ben birkaç ay önce C # ffmpeg ile çalışmak için bir yardımcı program yazdı. Bunu yapmak için normal ifadeler kullanılır. Oradan size yardımcı olabilecek bazı düzenli ifadeler vardır:

// this is for version detection
"FFmpeg version (?<version>(\w|\d|\.|-)+)"
// this is for duration parsing
"Duration: (?<hours>\d{1,3}):(?<minutes>\d{2}):(?<seconds>\d{2})(.(?<fractions>\d{1,3}))?"

// these are connected:
// 0) this is base for getting stream info
"Stream #(?<number>\d+?\.\d+?)(\((?<language>\w+)\))?: (?<type>.+): (?<data>.+)"
// 1) if the type is audio:
"(?<codec>\w+), (?<frequency>[\d]+) (?<frequencyUnit>[MK]?Hz), (?<chanel>\w+), (?<format>\w+)(, (?<bitrate>\d+) (?<bitrateUnit>[\w/]+))?"
// 2) if the type is video:
"(?<codec>\w+), (?<format>\w+), (?<width>\d+)x(?<height>\d+), (?<bitrate>\d+(\.\d+)?) (?<bitrateUnit>[\w\(\)]+)"

Yani genişliğini ve yüksekliğini alıyorum boy oranını hesaplayabilirsiniz.

Not: Bazı durumlarda orada ifadeler başarısız olabilir biliyorum.