node.js تحميل - أفضل طريقة إلى http في الوقت الحقيقي المتدفقة إلى عميل الفيديو HTML5



ماهو video (9)

أنا حقا عالقة في محاولة لفهم أفضل طريقة لتدفق الإخراج في الوقت الحقيقي من ffmpeg إلى عميل HTML5 باستخدام node.js ، حيث أن هناك عددا من المتغيرات في اللعب وليس لدي الكثير من الخبرة في هذا الفضاء ، لقد قضيت عدة ساعات في محاولة تركيبات مختلفة.

حالة استخدامي هي:

1) يتم التقاط دفق الفيديو IP RTSP H.264 بواسطة FFMPEG وإعادة إدخالها في حاوية mp4 باستخدام إعدادات FFMPEG التالية في العقدة ، الإخراج إلى STDOUT. يتم تشغيل هذا فقط على اتصال العميل الأولي ، بحيث لا تحاول طلبات المحتوى الجزئية إنتاج FFMPEG مرة أخرى.

liveFFMPEG = child_process.spawn("ffmpeg", [
                "-i", "rtsp://admin:[email protected]:554" , "-vcodec", "copy", "-f",
                "mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov", 
                "-"   // output to stdout
                ],  {detached: false});

2) يمكنني استخدام خادم http العقدة لالتقاط STDOUT وتدفق ذلك العودة إلى العميل بناء على طلب العميل. عند اتصال العميل أولاً ، قمت بإنتاج سطر الأوامر FFMPEG أعلاه ثم توجيه تدفق STDOUT إلى استجابة HTTP.

liveFFMPEG.stdout.pipe(resp);

لقد استخدمت أيضًا حدث البث لكتابة بيانات FFMPEG إلى استجابة HTTP ولكن لا فرق

xliveFFMPEG.stdout.on("data",function(data) {
        resp.write(data);
}

أستخدم عنوان HTTP التالي (والذي يستخدم أيضًا ويعمل عند تدفق الملفات المسجلة مسبقًا)

var total = 999999999         // fake a large file
var partialstart = 0
var partialend = total - 1

if (range !== undefined) {
    var parts = range.replace(/bytes=/, "").split("-"); 
    var partialstart = parts[0]; 
    var partialend = parts[1];
} 

var start = parseInt(partialstart, 10); 
var end = partialend ? parseInt(partialend, 10) : total;   // fake a large file if no range reques 

var chunksize = (end-start)+1; 

resp.writeHead(206, {
                  'Transfer-Encoding': 'chunked'
                 , 'Content-Type': 'video/mp4'
                 , 'Content-Length': chunksize // large size to fake a file
                 , 'Accept-Ranges': 'bytes ' + start + "-" + end + "/" + total
});

3) يجب على العميل استخدام علامات فيديو HTML5.

ليس لدي أي مشاكل مع تشغيل البث (باستخدام fs.createReadStream مع المحتوى الجزئي 206 HTTP) إلى عميل HTML5 ملف فيديو تم تسجيله مسبقًا باستخدام سطر الأوامر FFMPEG أعلاه (ولكن تم حفظه في ملف بدلاً من STDOUT) ، لذلك أعرف تدفق FFMPEG صحيح ، ويمكنني أن أرى بشكل صحيح الفيديو بث مباشر في VLC عند الاتصال بخادم عقدة HTTP.

ومع ذلك ، فإن محاولة البث المباشر من FFMPEG عبر العقدة HTTP يبدو أصعب بكثير حيث سيعرض العميل إطارًا واحدًا ثم يتوقف. أظن أن المشكلة تكمن في أنني لا أقوم بإعداد اتصال HTTP لتكون متوافقة مع عميل الفيديو HTML5. لقد جربت مجموعة متنوعة من الأشياء مثل استخدام HTTP 206 (محتوى جزئي) و 200 رد ، ووضع البيانات في مخزن مؤقت ثم تدفق بدون حظ ، لذلك أحتاج إلى الرجوع إلى المبادئ الأولى للتأكد من إعداد هذا الحق الطريقة.

في ما يلي فهمي لكيفية العمل ، الرجاء تصحيح ذلك إذا كنت مخطئًا:

1) يجب إعداد FFMPEG لتفتيت المخرجات واستخدام moov فارغ (FFMPEG frag_keyframe وعلامات mov_val). هذا يعني أن العميل لا يستخدم ذرة moov التي عادة ما تكون في نهاية الملف والتي لا تكون ذات صلة عند البث (لا نهاية للملف) ، ولكنها تعني عدم البحث عن الأمر الذي يكون مناسبًا لحالتي في الاستخدام.

2) على الرغم من أنني أستخدم شظايا MP4 و MOOV فارغة ، فلا يزال يتعين علي استخدام محتوى جزئي لـ HTTP ، حيث سينتظر مشغل HTML5 حتى يتم تنزيل مجموعة البث بالكامل قبل التشغيل ، والتي لا تنتهي أبدًا مع البث المباشر.

3) لا أفهم لماذا لا يعمل توجيه تدفق STDOUT إلى استجابة HTTP عند البث المباشر بعد إذا حفظت إلى ملف يمكنني بث هذا الملف بسهولة إلى عملاء HTML5 باستخدام رمز مشابه. ربما تكون مشكلة توقيت لأنها تأخذ ثانية واحدة لبدء تذييل FFMPEG ، والاتصال بكاميرا IP وإرسال قطع إلى عقدة ، وأحداث البيانات عقدة غير منتظمة كذلك. ومع ذلك ، يجب أن يكون bytestream مطابقًا تمامًا للحفظ في ملف ، ويجب أن يكون HTTP قادرًا على تلبية حالات التأخير.

4) عند التحقق من سجل الشبكة من عميل HTTP عند دفق ملف MP4 تم إنشاؤه بواسطة FFMPEG من الكاميرا ، أرى أن هناك 3 طلبات عميل: طلب GET عام للفيديو ، والذي يقوم خادم HTTP بإرجاعه حوالي 40 كيلوبايت ، ثم جزئي طلب المحتوى مع نطاق بايت لآخر 10K من الملف ، ثم لم يتم تحميل طلب نهائي للبت في الوسط. ربما يطلب عميل HTML5 عندما يتلقى الاستجابة الأولى الجزء الأخير من الملف لتحميل ذرة MP4 MOOV؟ إذا كانت هذه هي الحالة ، فلن تعمل للبث لأنه لا يوجد ملف MOOV ولا نهاية للملف.

5) عند التحقق من سجل الشبكة عند محاولة البث المباشر ، أحصل على طلب أولي تم إجهاضه مع حوالي 200 بايت فقط تم تلقيه ، ثم تم إحباط طلب إعادة الطلب مرة أخرى مع 200 بايت وطلب ثالث يبلغ طوله 2 كيلو بايت فقط. لا أفهم سبب قيام عميل HTML5 بإحباط الطلب حيث أن bytestream هو نفسه تمامًا كما يمكنني استخدامه بنجاح عند البث من ملف مسجل. يبدو أيضًا أن العقدة لا ترسل بقية تدفق FFMPEG إلى العميل ، ولكن يمكنني رؤية بيانات FFMPEG في روتين الحدث .on بحيث يتم الوصول إلى خادم HTTP لعقدة FFMPEG.

6) على الرغم من أنني أعتقد أنه يجب أن تعمل أنابيب STDOUT stream إلى المخزن المؤقت استجابة HTTP ، هل يجب علي إنشاء مخزن مؤقت وسيطة تسمح لطلبات عميل المحتوى الجزئي لـ HTTP بالعمل بشكل صحيح كما يحدث عندما يقرأ ملف (بنجاح) ؟ أعتقد أن هذا هو السبب الرئيسي لمشاكلي ، لكنني لست متأكدًا من العقدة في كيفية إعداد ذلك. ولا أعرف كيفية التعامل مع طلب العميل للحصول على البيانات في نهاية الملف حيث لا توجد نهاية للملف.

7) هل أنا على المسار الخطأ بمحاولة التعامل مع 206 طلبات محتوى جزئية ، وهل يجب أن يعمل هذا مع استجابات HTTP 200 العادية؟ تعمل استجابات HTTP 200 بشكل جيد لـ VLC لذا أظن أن عميل الفيديو HTML5 سيعمل فقط مع طلبات المحتوى الجزئي؟

بما أنني لا أزال أتعلم هذه الأشياء يصعب العمل من خلال الطبقات المختلفة لهذه المشكلة (FFMPEG ، عقدة ، تدفق ، HTTP ، HTML5) لذا فإن أي مؤشرات ستكون موضع تقدير كبير. لقد قضيت ساعات في البحث في هذا الموقع والشبكة ، ولم أواجه أي شخص استطاع أن يفعل في الوقت الحقيقي تدفقًا في العقدة ولكنني لا أستطيع أن أكون أولًا ، وأعتقد أن هذا سيكون قادرًا على العمل (بطريقة ما !).


Answers

جرب binaryjs. انها مجرد مثل socket.io ولكن الشيء الوحيد الذي هو جيد هو أنه دفق الفيديو الصوتي. Binaryjs جوجل عليه


طريقة واحدة لتبث كاميرا ويب قائمة على RTSP إلى عميل HTML5 (تتضمن إعادة الترميز ، لذلك نتوقع فقدان الجودة وتحتاج إلى بعض طاقة وحدة المعالجة المركزية):

  • إعداد خادم iCecast (يمكن أن يكون على نفس الجهاز الذي يعمل عليه خادم الويب أو على الجهاز الذي يتلقى تدفق RTSP من الكاميرا)
  • على الجهاز الذي يستقبل البث من الكاميرا ، لا تستخدم FFMPEG لكن gstreamer. وهو قادر على استقبال وفك تشفير RTSP-stream ، وإعادة ترميزه وتدفقه إلى خادم icecast. مثال على خط أنابيب (فيديو فقط ، بدون صوت):

    gst-launch-1.0 rtspsrc location=rtsp://192.168.1.234:554 user-id=admin user-pw=123456 ! rtph264depay ! avdec_h264 ! vp8enc threads=2 deadline=10000 ! webmmux streamable=true ! shout2send password=pass ip=<IP_OF_ICECAST_SERVER> port=12000 mount=cam.webm
    

=> يمكنك بعد ذلك استخدام علامة <video> مع عنوان URL الخاص بـ iicecast-stream ( http://127.0.0.1:12000/cam.webm ) وستعمل في كل متصفح وجهاز يدعم webm


لقد كتبت مشغل فيديو HTML5 حول برنامج ترميز h264 برودواي (emscripten) الذي يمكن أن يقوم بتشغيل الفيديو h264 المباشر (بدون تأخير) على جميع المتصفحات (سطح المكتب ، iOS ، ...).

يتم إرسال تدفق الفيديو من خلال websocket إلى العميل ، فك الإطار لكل إطار وعرضه في canva (باستخدام webgl للتسريع)

تحقق من https://github.com/131/h264-live-player على جيثب.


ألقِ نظرة على مشروع JSMPEG . هناك فكرة رائعة تم تنفيذها هناك - لفك شفرة MPEG في المتصفح باستخدام JavaScript. يمكن نقل وحدات البايت من برنامج التشفير (FFMPEG ، على سبيل المثال) إلى المتصفح باستخدام WebSockets أو Flash ، على سبيل المثال. إذا كان المجتمع سيصطدم ، أعتقد أنه سيكون أفضل حل بث الفيديو المباشر HTML5 في الوقت الحالي.


هذا هو مفهوم خاطئ شائع للغاية. لا يوجد دعم فيديو HTML5 (باستثناء HLS على iOS و Mac Safari). قد تكون قادرًا على "الاختراق" باستخدام حاوية ويب ، لكنني لا أتوقع أن تكون مدعومة عالميًا. يتم تضمين ما تبحث عنه في "ملحقات مصدر الوسائط" ، حيث يمكنك تغذية الأجزاء إلى المستعرض الواحد في كل مرة. ولكنك ستحتاج إلى كتابة بعض javascript من جانب العميل.


EDIT 3: اعتبارًا من IOS 10 ، يدعم HLS ملفات MP4 المجزأة. الجواب الآن ، هو إنشاء أصول mp4 مجزأة ، مع بيان DASH و HLS. > التظاهر فلاش ، iOS9 وأقل و IE 10 وأقل لا وجود لها.

كل شيء تحت هذا السطر قديم. ابقائها هنا للأجيال القادمة.

تحرير 2: كما يشير الناس في التعليقات ، تتغير الأمور. سوف تدعم جميع المتصفحات تقريبًا برامج ترميز AVC / AAC. iOS لا يزال يتطلب HLS. ولكن من خلال محولات مثل hls.js يمكنك لعب HLS في MSE. الإجابة الجديدة هي HLS + hls.js إذا كنت بحاجة إلى نظام iOS. أو مجرد Fragmented MP4 (أي DASH) إذا لم تقم بذلك

هناك العديد من الأسباب التي تجعل الفيديو ، وخاصة الفيديو المباشر ، أمرًا صعبًا للغاية. (يرجى ملاحظة أن السؤال الأصلي حدد أن فيديو HTML5 هو مطلب ، لكن المسجل ذكر أن Flash ممكن في التعليقات. لذلك على الفور ، هذا السؤال مضلل)

أولاً سأذكر: لا يوجد دعم رسمي للتدفق المباشر عبر HTML5 . هناك اختراقات ، لكن الأميال الخاصة بك قد تختلف.

تحرير: منذ أن كتبت هذا الجواب نضجت وسائل الإعلام المصدر ، والآن قريبة جدا من أن تصبح خيارا قابلا للتطبيق. وهي مدعومة في معظم المتصفحات الرئيسية. لا يزال IOS يثبت.

بعد ذلك ، تحتاج إلى فهم أن الفيديو حسب الطلب (VOD) والفيديو المباشر مختلفان تمامًا. نعم ، كلاهما فيديو ، لكن المشاكل مختلفة ، وبالتالي الأشكال مختلفة. على سبيل المثال ، إذا كانت الساعة في جهاز الكمبيوتر تعمل بنسبة 1٪ أسرع مما ينبغي ، فلن تلاحظ على VOD. باستخدام الفيديو المباشر ، ستحاول تشغيل الفيديو قبل حدوثه. إذا كنت تريد الانضمام إلى دفق فيديو مباشر قيد التقدم ، فستحتاج إلى البيانات الضرورية لتهيئة مفكك التشفير ، لذا يجب تكرارها في الدفق ، أو إرسالها خارج النطاق. باستخدام VOD ، يمكنك قراءة بداية الملف بحثًا عن النقطة التي تريدها.

الآن دعونا حفر قليلا.

منصات:

  • دائرة الرقابة الداخلية
  • الكمبيوتر
  • ماك
  • ذكري المظهر

الترميز:

  • VP8 / 9
  • H.264
  • ثورا (vp3)

طرق التسليم الشائعة للفيديو المباشر في المتصفحات:

  • DASH (HTTP)
  • HLS (HTTP)
  • فلاش (RTMP)
  • فلاش (HDS)

طرق التسليم الشائعة لـ VOD في المتصفحات:

  • DASH (تدفق HTTP)
  • HLS (تدفق HTTP)
  • فلاش (RTMP)
  • فلاش (تدفق HTTP)
  • MP4 (تدفق pseudo HTTP)
  • لن أتحدث عن MKV و OOG لأنني لا أعرفهم جيدًا.

علامة html5 للفيديو:

  • MP4
  • ويب إم
  • سطين

دعونا نلقي نظرة على المتصفحات التي تدعم ما الأشكال

سفاري:

  • HLS (iOS و mac فقط)
  • H.264
  • MP4

ثعلب النار

  • DASH (عبر MSE لكن لا يوجد h.264)
  • h.264 عبر فلاش فقط!
  • VP9
  • MP4
  • OGG
  • ويب إم

أي

  • فلاش
  • DASH (عبر MSE IE 11+ فقط)
  • H.264
  • MP4

كروم

  • فلاش
  • DASH (عبر MSE)
  • H.264
  • VP9
  • MP4
  • ويب إم
  • سطين

لا يمكن استخدام MP4 للفيديو المباشر (ملاحظة: DASH هي مجموعة شاملة من MP4 ، لذلك لا يتم الخلط بينها وبين ذلك). يتم تقسيم MP4 إلى قسمين: moov و mdat. يحتوي mdat على بيانات الفيديو الصوت الخام. ولكنها ليست مفهرسة ، لذلك بدون الموف ، فلا فائدة منها. يحتوي moov على فهرس لكل البيانات في mdat. ولكن نظرًا لشكله ، فإنه لا يمكن "تسويته" حتى يتم التعرف على الطوابع الزمنية وحجم كل إطار. قد يكون من الممكن بناء moov التي "fibs" أحجام الإطار ، ولكن هو عرض النطاق الترددي wasteful جداً.

لذلك إذا كنت ترغب في تقديم كل مكان ، فنحن بحاجة إلى العثور على القاسم المشترك الأقل. سترى أنه لا يوجد LCD هنا دون اللجوء إلى مثال فلاش:

  • يدعم نظام التشغيل iOS فقط الفيديو h.264. ويدعم فقط HLS للعيش.
  • لا يدعم متصفح Firefox h.264 مطلقًا ، ما لم تستخدم الفلاش
  • لا يعمل الفلاش في iOS

إن أقرب شيء إلى LCD هو استخدام HLS للحصول على مستخدمي iOS الخاص بك ، ومضة لأي شخص آخر. بلدي المفضل الشخصي هو ترميز HLS ، ثم استخدام الفلاش لتشغيل HLS للجميع. يمكنك تشغيل HLS في Flash عبر JW player 6 ، (أو كتابة HLS الخاص بك إلى FLV في AS3 كما فعلت)

قريبًا ، ستكون أكثر الطرق شيوعًا للقيام بذلك هي HLS على نظامي iOS / Mac و DASH عبر MSE في أي مكان آخر (وهذا ما ستقوم به Netflix قريبًا). ولكننا لا نزال ننتظر من الجميع ترقية متصفحاتهم. من المحتمل أن تحتاج أيضًا إلى DASH / VP9 منفصل لمتصفح فايرفوكس (أعرفه حول open264 ، إنه يمتص. لا يمكنه فعل الفيديو في الملف الرئيسي أو الملف الشخصي العالي. لذا فهو غير مفيد حاليًا).


شكراً للجميع خاصة szatmary حيث أن هذا سؤال معقد وله العديد من الطبقات ، كل ذلك يجب أن يعمل قبل أن تتمكن من بث الفيديو المباشر. لتوضيح سؤالي الأصلي واستخدام فيديو HTML5 مقارنة بالفلاش - تتمتع حالة الاستخدام بتفضيل قوي لـ HTML5 لأنها عامة وسهلة التنفيذ على العميل والمستقبل. يُعد الفلاش ثاني أفضل حلٍ بعيدًا لذا يتيح لك التواجد باستخدام HTML5 لهذا السؤال.

لقد تعلمت الكثير من خلال هذا التمرين وأوافق على البث المباشر أصعب بكثير من VOD (الذي يعمل بشكل جيد مع فيديو HTML5). لكنني حصلت على هذا العمل بشكل مرضٍ لحالة الاستخدام الخاصة بي ، وتم التوصل إلى حل بسيط للغاية ، بعد مطاردة المزيد من الخيارات المعقدة مثل MSE ، flash ، مخططات التخزين المفصّلة في Node. كانت المشكلة أن FFMPEG كان يفسد MP4 مجزأة واضطررت لضبط معاملات FFMPEG ، وإعادة توجيه أنبوبة تدفق العقدة القياسية على http التي كنت في الأصل كانت كل ما هو مطلوب.

في MP4 ، يوجد خيار "التجزئة" يكسر mp4 إلى أجزاء أصغر بكثير والتي تحتوي على فهرس خاص بها ويجعل خيار البث المباشر mp4 قابلاً للتطبيق. ولكن ليس من الممكن البحث مرة أخرى في الدفق (موافق لحالة الاستخدام الخاصة بي) ، والإصدارات الأحدث من تجزئة دعم FFMPEG.

ملاحظة التوقيت قد يكون مشكلة ، وبحلولتي ، لديّ فترة تأخير تتراوح بين 2 و 6 ثوانٍ بسبب توليفة من إعادة الضبط (على نحو فعال ، يجب على FFMPEG استقبال البث المباشر ، وإعادة إرساله ثم إرساله إلى العقدة للخدمة عبر HTTP) . ليس هناك الكثير الذي يمكن عمله حيال ذلك ، ولكن في Chrome يحاول الفيديو اللحاق بأكبر قدر ممكن مما يجعل الفيديو أكثر ثباتًا ولكن أكثر من IE11 (العميل المفضل).

بدلاً من شرح كيفية عمل التعليمة البرمجية في هذه المشاركة ، تحقق من GIST مع التعليقات (لم يتم تضمين رمز العميل ، بل هو علامة فيديو قياسية HTML5 مع عنوان خادم http العقدة). GIST هنا: https://gist.github.com/deandob/9240090

لم أتمكن من العثور على أمثلة مشابهة لحالة الاستخدام هذه ، لذلك آمل أن يساعد التوضيح والرمز أعلاه على الآخرين ، خاصة وأنني تعلمت الكثير من هذا الموقع وما زلت أعتبر نفسي مبتدئًا!

على الرغم من أن هذا هو الإجابة على سؤالي المحدد ، فقد اخترت إجابة szatmary كإجابة مقبولة لأنها الأكثر شمولية.


الق نظرة على هذا الحل . كما أعلم ، Flashphoner يسمح بتشغيل بث صوتي + فيديو مباشر في صفحة HTML5 الخالصة.

وهي تستخدم برامج الترميز MPEG1 و G.711 للتشغيل. يعمل الاختراق على عرض مقطع الفيديو الذي تم فك ترميزه إلى عنصر قماش HTML5 وتشغيل صوت فك الشفرة عبر سياق HTML5 الصوتي.


يبدو أن العديد من الملفات والدلائل في /usr/local هي الآن مملوكة root ، حيث قمت بتشغيل بضع خطوات باستخدام sudo . للتخلص من هذه ، استرجع ملكية جميع الملفات والدلائل تحت /usr/local :

sudo chown -R $USER /usr/local

بمجرد أن يتم ذلك ، قم بتشغيل brew doctor مرة أخرى.

يمكن العثور على أسئلة مماثلة هنا:





html5 node.js ffmpeg streaming