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


Answers

شكراً للجميع خاصة 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 كإجابة مقبولة لأنها الأكثر شمولية.

Question

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

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

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

liveFFMPEG = child_process.spawn("ffmpeg", [
                "-i", "rtsp://admin:12345@192.168.1.234: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) لذا فإن أي مؤشرات ستكون موضع تقدير كبير. لقد قضيت ساعات في البحث في هذا الموقع والشبكة ، ولم أواجه أي شخص استطاع أن يفعل في الوقت الحقيقي تدفقًا في العقدة ولكنني لا أستطيع أن أكون أولًا ، وأعتقد أن هذا سيكون قادرًا على العمل (بطريقة ما !).




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




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

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

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




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

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