Zusammenfassend
Es ist einfach, es in Firefox und Chrome zum Laufen zu bringen: Sie müssen lediglich einen Audio-Codec zu Ihrer Codec-Liste hinzufügen! video/webm;codecs=opus,vp8
Es ist wesentlich komplizierter, es in Safari zum Laufen zu bringen. MediaRecorder ist eine "experimentelle" Funktion, die unter den Entwickleroptionen manuell aktiviert werden muss. Nach der Aktivierung fehlt Safari eine isTypeSupported
Methode, daher müssen Sie damit umgehen. Unabhängig davon, was Sie vom MediaRecorder anfordern, erhalten Sie von Safari immer eine MP4-Datei, die nicht wie WEBM gestreamt werden kann. Dies bedeutet, dass Sie Transmuxing in JavaScript durchführen müssen, um das Videocontainerformat im laufenden Betrieb zu konvertieren
Android sollte funktionieren, wenn Chrome funktioniert
iOS unterstützt keine Media Source Extensions, SourceBuffer
ist also unter iOS nicht definiert und die gesamte Lösung funktioniert nicht
Ursprünglicher Beitrag
Wenn Sie sich die von Ihnen veröffentlichte JSFiddle ansehen, eine kurze Lösung, bevor wir beginnen:
- Sie verweisen auf eine Variable,
errorMsgElement
die niemals definiert ist. Sie sollten <div>
der Seite eine mit einer entsprechenden ID hinzufügen und dann eine const errorMsgElement = document.querySelector(...)
Linie erstellen , um sie zu erfassen
Wenn Sie mit Media Source Extensions und MediaRecorder arbeiten, sollten Sie beachten, dass die Unterstützung je nach Browser sehr unterschiedlich sein wird. Obwohl dies ein "standardisierter" Teil der HTML5-Spezifikation ist, ist er plattformübergreifend nicht sehr konsistent. Nach meiner Erfahrung ist es nicht allzu schwierig, MediaRecorder in Firefox zum Laufen zu bringen. Es ist etwas schwieriger, es in Chrome zum Laufen zu bringen. Es ist fast unmöglich, es in Safari zum Laufen zu bringen, und es funktioniert buchstäblich nicht unter iOS etwas, was du tun kannst.
Ich habe dies pro Browser durchgesehen und debuggt und meine Schritte aufgezeichnet, damit Sie einige der Tools verstehen, die Ihnen beim Debuggen von Medienproblemen zur Verfügung stehen
Feuerfuchs
Beim Auschecken Ihrer JSFiddle in Firefox wurde der folgende Fehler in der Konsole angezeigt:
NotSupportedError: Eine Audiospur kann nicht aufgezeichnet werden: video / webm; codecs = vp8 zeigt einen nicht unterstützten Codec an
Ich erinnere mich, dass VP8 / VP9 große Pushs von Google waren und als solche in Firefox möglicherweise nicht funktionieren. Deshalb habe ich versucht, eine kleine Änderung an Ihrem Code vorzunehmen. Ich habe den , options)
Parameter aus Ihrem Aufruf von entfernt new MediaRecorder()
. Dies weist den Browser an, den gewünschten Codec zu verwenden, sodass Sie wahrscheinlich in jedem Browser eine andere Ausgabe erhalten (dies sollte jedoch zumindest in jedem Browser funktionieren ).
Dies funktionierte in Firefox, also habe ich Chrome ausgecheckt.
Chrom
Diesmal habe ich einen neuen Fehler bekommen:
(Index): 409 Nicht erfasst (im Versprechen) DOMException: Fehler beim Ausführen von 'appendBuffer' für 'SourceBuffer': Dieser SourceBuffer wurde aus der übergeordneten Medienquelle entfernt. unter MediaRecorder.handleDataAvailable ( https://fiddle.jshell.net/43rm7258/1/show/:409:22 )
Also ging ich in meinem Browser zu chrome: // media-internals / und sah Folgendes:
Das Audio-Stream-Codec-Opus stimmt nicht mit den SourceBuffer-Codecs überein.
In Ihrem Code geben Sie einen Video-Codec (VP9 oder VP8) an, jedoch keinen Audio-Codec. Der MediaRecorder lässt den Browser also einen beliebigen Audio-Codec auswählen. Es sieht so aus, als würde in Chrome MediaRecorder standardmäßig "opus" als Audio-Codec ausgewählt, in Chrome SourceBuffer wird jedoch standardmäßig etwas anderes ausgewählt. Dies wurde trivial behoben. Ich habe Ihre beiden Zeilen aktualisiert, die Folgendes festlegen options.mimeType
:
options = { mimeType: "video/webm;codecs=opus, vp9" };
options = { mimeType: "video/webm;codecs=opus, vp8" };
Da Sie dasselbe options
Objekt zum Deklarieren des MediaRecorders und des SourceBuffers verwenden, bedeutet das Hinzufügen des Audio-Codecs zur Liste, dass der SourceBuffer jetzt mit einem gültigen Audio-Codec deklariert wird und das Video abgespielt wird
Zum guten Teil habe ich den neuen Code (mit einem Audio-Codec) auf Firefox getestet. Das hat funktioniert! Wir sind also 2 für 2, indem wir einfach den Audio-Codec zur options
Liste hinzufügen (und ihn in den Parametern zum Deklarieren des MediaRecorders belassen).
Es sieht so aus, als ob VP8 und Opus in Firefox funktionieren, sind aber nicht die Standardeinstellungen (obwohl im Gegensatz zu Chrome die Standardeinstellungen für MediaRecorder und SourceBuffer dieselben sind, weshalb das Entfernen des options
Parameters vollständig funktioniert hat).
Safari
Diesmal haben wir einen Fehler erhalten, den wir möglicherweise nicht beheben können:
Nicht behandelte Ablehnung von Versprechungen: ReferenceError: Variable: MediaRecorder kann nicht gefunden werden
Das erste, was ich tat, war Google "Safari MediaRecorder", das diesen Artikel auftauchte . Ich dachte, ich würde es versuchen, also warf ich einen Blick darauf. Sicher genug:
Ich habe darauf geklickt, um MediaRecorder zu aktivieren, und in der Konsole wurde Folgendes festgestellt:
Nicht behandelte Ablehnung von Versprechungen: TypeError: MediaRecorder.isTypeSupported ist keine Funktion. (In 'MediaRecorder.isTypeSupported (options.mimeType)' ist 'MediaRecorder.isTypeSupported' undefiniert.)
Safari hat also nicht die isTypeSupported
Methode. Keine Sorge, wir sagen nur: "Wenn diese Methode nicht existiert, nehmen Sie an, dass es sich um Safari handelt, und stellen Sie den Typ entsprechend ein."
if (MediaRecorder.isTypeSupported) {
options = { mimeType: "video/webm;codecs=vp9" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm;codecs=vp8" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "" };
}
}
}
} else {
options = { mimeType: "" };
}
Jetzt musste ich nur noch einen mimeType finden, den Safari unterstützte. Etwas leichtes Googeln deutet darauf hin, dass H.264 unterstützt wird, also habe ich versucht:
options = { mimeType: "video/webm;codecs=h264" };
Dies gab mir erfolgreich MediaRecorder started
, scheiterte aber an der Zeile addSourceBuffer
mit dem neuen Fehler:
NotSupportedError: Der Vorgang wird nicht unterstützt.
Ich werde weiterhin versuchen, zu diagnostizieren, wie dies in Safari funktioniert, aber im Moment habe ich zumindest Firefox und Chrome angesprochen
Update 1
Ich habe weiter an Safari gearbeitet. Leider fehlt Safari das Tool von Chrome und Firefox, um tief in die Medieninternale einzudringen, sodass viele Vermutungen erforderlich sind.
Ich hatte zuvor herausgefunden, dass beim Versuch, einen Anruf zu tätigen, die Fehlermeldung "Der Vorgang wird nicht unterstützt" angezeigt wird addSourceBuffer
. Deshalb habe ich eine einmalige Seite erstellt, um zu versuchen, genau diese Methode unter verschiedenen Umständen aufzurufen:
- Fügen Sie möglicherweise einen Quellpuffer hinzu, bevor
play
das Video aufgerufen wird
- Fügen Sie möglicherweise einen Quellpuffer hinzu, bevor die Medienquelle an ein Videoelement angehängt wurde
- Fügen Sie möglicherweise einen Quellpuffer mit verschiedenen Codecs hinzu
- usw
Ich stellte fest, dass das Problem immer noch der Codec war und dass die Fehlermeldung, dass die "Operation" nicht zulässig war, leicht irreführend war. Es waren die Parameter , die nicht erlaubt waren. Die einfache Angabe von "h264" funktionierte für den MediaRecorder, aber für den SourceBuffer musste ich die Codec-Parameter weitergeben .
Eines der ersten Dinge, die ich versuchte, war, zur MDN-Beispielseite zu gehen und die dort verwendeten Codecs zu kopieren : 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
. Dies ergab den gleichen Fehler "Operation nicht zulässig". Graben in die Bedeutung dieser Codec - Parameter (wie das, was zum Teufel ist 42E01E
auch bedeuten ?). Während ich wünschte, ich hätte eine bessere Antwort, stieß ich beim Googeln auf diesen StackOverflow-Beitrag, in dem die Verwendung 'video/mp4; codecs="avc1.64000d,mp4a.40.2"'
auf Safari erwähnt wurde. Ich habe es ausprobiert und die Konsolenfehler waren weg!
Obwohl die Konsolenfehler jetzt verschwunden sind, sehe ich immer noch kein Video. Es gibt also noch viel zu tun.
Update 2
Weitere Untersuchungen im Debugger in Safari (Platzieren mehrerer Haltepunkte und Überprüfen von Variablen in jedem Schritt des Prozesses) ergaben, dass handleDataAvailable
dies in Safari nie aufgerufen wurde. Es sieht so aus, als würde Firefox und Chrome mediaRecorder.start(100)
der Spezifikation ordnungsgemäß folgen und ondatavailable
alle 100 Millisekunden aufrufen , aber Safari ignoriert den Parameter und puffert alles in einem massiven Blob. Manuelles mediaRecorder.stop()
Anrufen führte ondataavailable
dazu, dass mit allem, was bis zu diesem Zeitpunkt aufgezeichnet wurde, angerufen wurde
Ich habe versucht setInterval
, mediaRecorder.requestData()
alle 100 Millisekunden aufzurufen , requestData
wurde aber in Safari nicht definiert (ähnlich wie isTypeSupported
nicht definiert). Das hat mich ein bisschen in Schwierigkeiten gebracht.
Als nächstes habe ich versucht, das gesamte MediaRecorder-Objekt zu bereinigen und alle 100 Millisekunden ein neues zu erstellen, aber dies warf einen Fehler in die Zeile await bufferedBlob.arrayBuffer()
. Ich untersuche immer noch, warum dieser fehlgeschlagen ist
Update 3
Eine Sache, an die ich mich beim MP4-Format erinnere, ist, dass das "moov" -Atom benötigt wird, um Inhalte wiederzugeben . Aus diesem Grund können Sie die mittlere Hälfte einer MP4-Datei nicht herunterladen und abspielen. Sie müssen die GANZE Datei herunterladen. Ich fragte mich, ob die Tatsache, dass ich MP4 ausgewählt hatte, der Grund war, warum ich keine regelmäßigen Updates erhielt.
Ich habe versucht, video/mp4
auf einige andere Werte umzusteigen, und dabei unterschiedliche Ergebnisse erzielt:
video/webm
- Der Betrieb wird nicht unterstützt
video/x-m4v
- Ich habe mich wie MP4 verhalten und nur dann Daten erhalten, wenn sie .stop()
aufgerufen wurden
video/3gpp
- Benahm sich wie MP4
video/flv
- Der Betrieb wird nicht unterstützt
video/mpeg
- Benahm sich wie MP4
Alles, was sich wie MP4 verhält, hat mich dazu gebracht, die Daten zu überprüfen, an die tatsächlich weitergegeben wurde handleDataAvailable
. Da bemerkte ich Folgendes:
Egal was ich für das Videoformat ausgewählt habe, Safari hat mir immer einen MP4 gegeben!
Plötzlich erinnerte ich mich daran, warum Safari so ein Albtraum war und warum ich es mental als "fast unmöglich" eingestuft hatte. Um mehrere MP4s zusammenzufügen, wäre ein JavaScript-Transmuxer erforderlich
Da erinnerte ich mich, genau das hatte ich zuvor getan . Ich habe vor etwas mehr als einem Jahr mit MediaRecorder und SourceBuffer zusammengearbeitet, um einen JavaScript-RTMP-Player zu erstellen. Sobald der Player fertig war, wollte ich Unterstützung für DVR hinzufügen (Suche nach Teilen des bereits gestreamten Videos), indem ich MediaRecorder verwendete und einen Ringpuffer im Speicher von 1-Sekunden-Video-Blobs aufbewahrte. Auf Safari habe ich diese Video-Blobs über den Transmuxer ausgeführt, den ich codiert hatte, um sie von MP4 in ISO-BMFF zu konvertieren, damit ich sie miteinander verketten konnte.
Ich wünschte, ich könnte den Code mit Ihnen teilen, aber alles gehört meinem alten Arbeitgeber - an diesem Punkt ist mir die Lösung verloren gegangen. Ich weiß, dass sich jemand die Mühe gemacht hat, FFMPEG mit emscripten in JavaScript zu kompilieren, sodass Sie dies möglicherweise nutzen können.