2012-10-24 13 views
6

मैं एचटीएमएल 5 वीडियो के साथ काम करने के लिए एक कस्टम वेब सर्वर ऐप को संशोधित करने की कोशिश कर रहा हूं।एचटीएमएल 5 वीडियो और आंशिक रेंज HTTP अनुरोध

यह एक मूलभूत <video> टैग के साथ एक HTML5 पृष्ठ परोसता है और फिर इसे वास्तविक सामग्री के अनुरोधों को संभालने की आवश्यकता होती है।

एकमात्र तरीका मैं इसे अब तक काम करने के लिए प्राप्त कर सकता हूं, पूरी वीडियो फ़ाइल को स्मृति में लोड करना है और फिर इसे एक ही प्रतिक्रिया में भेजना है। यह एक व्यावहारिक विकल्प नहीं है। मैं इसे टुकड़े से टुकड़ा करना चाहता हूं: वापस भेजो, कहें, 100 केबी, और ब्राउजर के लिए और अधिक अनुरोध करने का इंतजार करें। ,

HTTP/1.1 206 Partial content 
Content-Type: video/mp4 
Content-Range: bytes 0-99999/232725251 
Content-Length: 100000 

मैं कुछ अधिक प्राप्त अनुरोध प्राप्त के रूप में

इस प्रकार है:

http_version = 1.1 
request_method = GET 

Host = ###.###.###.###:## 
User-Agent = Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0 
Accept = video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5 
Accept-Language = en-US,en;q=0.5 
Connection = keep-alive 
Range = bytes=0- 

मैं एक आंशिक सामग्री प्रतिक्रिया वापस भेजने की कोशिश की:

मैं निम्नलिखित हेडर के साथ अनुरोध दिखाई

Cache-Control = no-cache 
Connection = Keep-Alive 
Pragma = getIfoFileURI.dlna.org 
Accept = */* 
User-Agent = NSPlayer/12.00.7601.17514 WMFSDK/12.00.7601.17514 
GetContentFeatures.DLNA.ORG = 1 
Host = ###.###.###.###:## 

(कोई संकेत नहीं कि ब्राउज़र फ़ाइल का कोई विशिष्ट हिस्सा चाहता है।) कोई फर्क नहीं पड़ता कि मैं बीएसी भेजता हूं ब्राउज़र के लिए के, वीडियो नहीं खेलता है।

जैसा कि ऊपर बताया गया है, वही वीडियो ठीक से खेलेंगे यदि मैं एक ही HTTP पैकेट में एक बार में 230 एमबी फ़ाइल भेजने की कोशिश करता हूं।

क्या आंशिक सामग्री अनुरोधों के माध्यम से यह सब अच्छी तरह से काम करने का कोई तरीका है? मैं परीक्षण उद्देश्यों के लिए फ़ायरफ़ॉक्स का उपयोग कर रहा हूं, लेकिन इसे अंततः सभी ब्राउज़रों के साथ काम करने की ज़रूरत है।

+0

मैं यह अजीब आप परीक्षण के लिए Firefox का उपयोग कर रहे हैं और एक MP4 फ़ाइल जो फ़ायरफ़ॉक्स का समर्थन नहीं करता भेजने कि लगता है, तो यह काम कभी नहीं करना चाहिए। –

+0

अब तक मैंने फ़ायरफ़ॉक्स (H264 प्लगइन के साथ) और ब्राउज़र पक्ष पर IE9 और सर्वर पक्ष पर एमपी 4 और वेबएम की कोशिश की है। मुझे लगता है कि मुझे कुछ याद आ रही है। – user434507

+0

आप ग्राहकों से आंशिक रेंज अनुरोध क्यों प्राप्त करना चाहते हैं? बस उनसे पूछने की अनुमति दें कि वे क्या चाहते हैं, और उन्हें सबसे सुविधाजनक तरीके से भेजें। मैंने ऑडियो स्ट्रीमिंग (क्रोम से अनुरोध किया) के साथ काम किया, और एक कस्टम सर्वर - यह वास्तविक समय में ध्वनि भेजता है। मुझे लगता है कि यह डिफ़ॉल्ट और स्वीकार्य तरीका है। यदि आप नेटवर्क लोड के बारे में परेशान हैं, तो चिकनी वीडियो प्लेबैक के लिए पर्याप्त गति तक थ्रॉटलिंग का उपयोग करें। – Stan

उत्तर

4

मुझे पता है कि यह एक पुराना सवाल है, लेकिन अगर यह आपको निम्नलिखित "मॉडल" का प्रयास करने में मदद करता है जिसे हम अपने कोड बेस में उपयोग करते हैं।

class Model_DownloadableFile { 
private $full_path; 

function __construct($full_path) { 
    $this->full_path = $full_path; 
} 

public function get_full_path() { 
    return $this->full_path; 
} 

// Function borrowed from (been cleaned up and modified slightly): http://stackoverflow.com/questions/157318/resumable-downloads-when-using-php-to-send-the-file/4451376#4451376 
// Allows for resuming paused downloads etc 
public function download_file_in_browser() { 
    // Avoid sending unexpected errors to the client - we should be serving a file, 
    // we don't want to corrupt the data we send 
    @error_reporting(0); 

    // Make sure the files exists, otherwise we are wasting our time 
    if (!file_exists($this->full_path)) { 
     header('HTTP/1.1 404 Not Found'); 
     exit; 
    } 

    // Get the 'Range' header if one was sent 
    if (isset($_SERVER['HTTP_RANGE'])) { 
     $range = $_SERVER['HTTP_RANGE']; // IIS/Some Apache versions 
    } else if ($apache = apache_request_headers()) { // Try Apache again 
     $headers = array(); 
     foreach ($apache as $header => $val) { 
      $headers[strtolower($header)] = $val; 
     } 
     if (isset($headers['range'])) { 
      $range = $headers['range']; 
     } else { 
      $range = false; // We can't get the header/there isn't one set 
     } 
    } else { 
     $range = false; // We can't get the header/there isn't one set 
    } 

    // Get the data range requested (if any) 
    $filesize = filesize($this->full_path); 
    $length = $filesize; 
    if ($range) { 
     $partial = true; 
     list($param, $range) = explode('=', $range); 
     if (strtolower(trim($param)) != 'bytes') { // Bad request - range unit is not 'bytes' 
      header("HTTP/1.1 400 Invalid Request"); 
      exit; 
     } 
     $range = explode(',', $range); 
     $range = explode('-', $range[0]); // We only deal with the first requested range 
     if (count($range) != 2) { // Bad request - 'bytes' parameter is not valid 
      header("HTTP/1.1 400 Invalid Request"); 
      exit; 
     } 
     if ($range[0] === '') { // First number missing, return last $range[1] bytes 
      $end = $filesize - 1; 
      $start = $end - intval($range[0]); 
     } else if ($range[1] === '') { // Second number missing, return from byte $range[0] to end 
      $start = intval($range[0]); 
      $end = $filesize - 1; 
     } else { // Both numbers present, return specific range 
      $start = intval($range[0]); 
      $end = intval($range[1]); 
      if ($end >= $filesize || (!$start && (!$end || $end == ($filesize - 1)))) { 
       $partial = false; 
      } // Invalid range/whole file specified, return whole file 
     } 
     $length = $end - $start + 1; 
    } else { 
     $partial = false; // No range requested 
    } 

    // Determine the content type 
    $finfo = finfo_open(FILEINFO_MIME_TYPE); 
    $contenttype = finfo_file($finfo, $this->full_path); 
    finfo_close($finfo); 

    // Send standard headers 
    header("Content-Type: $contenttype"); 
    header("Content-Length: $length"); 
    header('Content-Disposition: attachment; filename="' . basename($this->full_path) . '"'); 
    header('Accept-Ranges: bytes'); 

    // if requested, send extra headers and part of file... 
    if ($partial) { 
     header('HTTP/1.1 206 Partial Content'); 
     header("Content-Range: bytes $start-$end/$filesize"); 
     if (!$fp = fopen($this->full_path, 'r')) { // Error out if we can't read the file 
      header("HTTP/1.1 500 Internal Server Error"); 
      exit; 
     } 
     if ($start) { 
      fseek($fp, $start); 
     } 
     while ($length) { // Read in blocks of 8KB so we don't chew up memory on the server 
      $read = ($length > 8192) ? 8192 : $length; 
      $length -= $read; 
      print(fread($fp, $read)); 
     } 
     fclose($fp); 
    } else { 
     readfile($this->full_path); // ...otherwise just send the whole file 
    } 

    // Exit here to avoid accidentally sending extra content on the end of the file 
    exit; 
} 
} 

फिर आप इस तरह उपयोग:

(new Model_DownloadableFile('FULL/PATH/TO/FILE'))->download_file_in_browser(); 

यह फ़ाइल या पूर्ण फ़ाइल आदि का भाग भेजना साथ सौदा है और इस में हमारे लिए अच्छी तरह से काम करता है और अन्य स्थितियों के बहुत सारे होगा। आशा करता हूँ की ये काम करेगा।

+1

वह पंक्ति जो शीर्षलेख ("सामग्री-लंबाई: $ filesize") पढ़ती है; वास्तव में शीर्षलेख होना चाहिए ("सामग्री-लंबाई: $ लंबाई"); क्योंकि यह कुल बाइट वितरित है, फ़ाइल का आकार नहीं। यदि सही ढंग से सेट नहीं किया गया है तो क्रोम के वीडियो प्लेयर बारफ इस पर हैं। – frankieandshadow

+0

अच्छी जगह, मैंने मूल पोस्ट को सही किया है। $ लंबाई केवल तभी सेट की जाती है जब $ रेंज सही हो, इसलिए मैंने यह सुनिश्चित कर लिया है कि यह पहले $ फाइलसाइज पर सेट हो गया है और $ श्रेणी सही होने पर ओवरराइट हो जाता है। –

+0

मेरी समस्या यह है कि php सामग्री-प्रकार प्रदान करता है: टेक्स्ट/एचटीएमएल अगर हेडर_remove ('कंटेन-टाइप'); –

1

मुझे आंशिक रेंज अनुरोध चाहिए, क्योंकि मैं रीयलटाइम ट्रांसकोडिंग कर रहा हूं, मेरे पास फाइल पूरी तरह से ट्रांसकोड नहीं हो सकती है और अनुरोध पर उपलब्ध नहीं हो सकती है।

प्रतिक्रिया है जो आप अभी तक पूरे शरीर की सामग्री पता नहीं है के लिए (आप Content-Length, लाइव एन्कोडिंग अनुमान नहीं कर सकते हैं), उपयोग हिस्सा एन्कोडिंग: भेजने

HTTP/1.1 200 OK 
Content-Type: video/mp4 
Transfer-Encoding: chunked 
Trailer: Expires 

1E; 1st chunk 
...binary....data...chunk1..my 
24; 2nd chunk 
video..binary....data....chunk2..con 
22; 3rd chunk 
tent...binary....data....chunk3..a 
2A; 4th chunk 
nd...binary......data......chunk4...etc... 
0 
Expires: Wed, 21 Oct 2015 07:28:00 GMT 

प्रत्येक हिस्सा है जब यह उपलब्ध है : जब कुछ फ्रेम इनकोड या जब उत्पादन बफर भरा हुआ है, 100KB, आदि

22; 3rd chunk 
tent...binary....data....chunk3..a 

कहाँ 22 हेक्सा में हिस्सा बाइट लंबाई (0x22 = 34 बाइट्स) देते हैं,उत्पन्न कर रहे हैं; 3rd chunk अतिरिक्त खंड इंफोस (वैकल्पिक) है और tent...binary....data....chunk3..a खंड की सामग्री है।

तब, जब एन्कोडिंग समाप्त हो गया है और सभी मात्रा द्वारा भेजे जाते हैं, अंत:

0 
Expires: Wed, 21 Oct 2015 07:28:00 GMT 

कहाँ 0 का मतलब यह नहीं अधिक मात्रा, शून्य या अधिक ट्रेलर (अनुमति हेडर फील्ड) के बाद हेडर में निर्धारित (Trailer: Expires और Expires: Wed, 21 Oct 2015 07:28:00 GMT की आवश्यकता नहीं है) चेकसम या डिजिटल हस्ताक्षर प्रदान करने के लिए, आदि

यहाँ

है सर्वर की प्रतिक्रिया के बराबर है, तो फ़ाइल पहले से जनरेट किया गया था (कोई लाइव एन्कोडिंग):

HTTP/1.1 200 OK 
Content-Type: video/mp4 
Content-Length: 142 
Expires: Wed, 21 Oct 2015 07:28:00 GMT 

...binary....data...chunk1..myvideo..binary....data....chunk2..content...binary....data....chunk3..and...binary......data......chunk4...etc... 

अधिक जानकारी के लिए: Chunked transfer encoding — Wikipedia, Trailer - HTTP | MDN

+0

मुझे नहीं लगता कि वीडियो टैग खंडित एन्कोडिंग (कम से कम क्रोम में) का समर्थन करता है। – themihai

+0

HTTP/1.1 समर्थन के लिए खंडित परिवहन एन्कोडिंग आवश्यक है। मैंने कोशिश की, क्रोम और फ़ायरफ़ॉक्स चंकित परिवहन एन्कोडिंग का उपयोग कर अच्छी तरह से वीडियो चलाते हैं। सफारी (डेस्कटॉप और आईओएस) की आवश्यकता है [श्रेणियां] (https://en.wikipedia.org/wiki/Byte_serving) वीडियो चलाने के लिए समर्थन (ऑडियो के लिए आवश्यक नहीं)। परिवहन एन्कोडिंग और श्रेणियां असंगत नहीं हैं, लेकिन बाइट श्रेणी को पहले बाइट आकार में जानना आवश्यक है। इसके लिए, आप लाइव स्ट्रीमिंग प्रोटोकॉल का उपयोग कर सकते हैं (लेकिन वीडियो एन्कोड करते समय विशेष उपचार की आवश्यकता होती है) जैसे एचएलएस या एमएसई जैसे एपीआई। देखें [hls.js] (https://github.com/video-dev/hls.js) – mems

+0

क्रोम आंशिक अनुरोध करता है भले ही सर्वर इसका समर्थन करता है या नहीं, इसलिए मुझे लगता है कि आंशिक/श्रेणी समर्थन के बिना अकेले चंकित एन्कोडिंग है एचटीएमएल 5 वीडियो की सेवा करने के लिए पर्याप्त नहीं है। यदि सर्वर सामग्री की कुल लंबाई का विज्ञापन नहीं करता है (यानी वाइल्डकार्ड प्रदान करता है *) खिलाड़ी अगले आंशिक अनुरोध के बाद अगले भाग का अनुरोध करने के बजाय पूरा हो जाता है तो मुझे लगता है कि यह एक क्रोम बग है। – themihai

संबंधित मुद्दे