Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

201 linhas
8.9 KiB

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>WebSocket MSE Fmp4 demo</title>
  6. </head>
  7. <body>
  8. <h1>MSE FMp4 Demo</h1>
  9. <video id="stream_live" width="640" height="480" controls="false" autoplay="true"
  10. muted="muted"
  11. preload="auto">
  12. 浏览器不支持
  13. </video>
  14. <ul id="messagesList"></ul>
  15. <script>
  16. //var mimeCodec = 'video/mp4;codecs="avc1.4D0014, mp4a.40.2"';
  17. // *** USER PARAMETERS ***
  18. var verbose = true;
  19. // var verbose = true; // enable for saturating the console ..
  20. var buffering_sec = 1; // use some reasonable value
  21. var buffering_sec_seek = buffering_sec * 0.9;
  22. // ..seek the stream if it's this much away or
  23. // from the last available timestamp
  24. var buffering_sec_seek_distance = buffering_sec * 0.5;
  25. // .. jump to this distance from the last avail. timestamp
  26. // *** INTERNAL PARAMETERS ***
  27. // set mimetype and codec
  28. var mimeType = "video/mp4";
  29. var codecs = "avc1.4D0014"; // https://wiki.whatwg.org/wiki/Video_type_parameters
  30. // if your stream has audio, remember to include it in these definitions.. otherwise your mse goes sour
  31. var codecPars = mimeType + ';codecs="' + codecs + '"';
  32. var stream_started = false; // is the source_buffer updateend callback active nor not
  33. // create media source instance
  34. var ms = new MediaSource();
  35. // queue for incoming media packets
  36. var queue = [];
  37. var stream_live; // the HTMLMediaElement (i.e. <video> element)
  38. var ws; // websocket
  39. var seeked = false; // have have seeked manually once ..
  40. var cc = 0;
  41. var source_buffer; // source_buffer instance
  42. var pass = 0;
  43. // *** MP4 Box manipulation functions ***
  44. // taken from here: https://stackoverflow.com/questions/54186634/sending-periodic-metadata-in-fragmented-live-mp4-stream/
  45. function toInt(arr, index) { // From bytes to big-endian 32-bit integer. Input: Uint8Array, index
  46. var dv = new DataView(arr.buffer, 0);
  47. return dv.getInt32(index, false); // big endian
  48. }
  49. function toString(arr, fr, to) { // From bytes to string. Input: Uint8Array, start index, stop index.
  50. // https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
  51. return String.fromCharCode.apply(null, arr.slice(fr, to));
  52. }
  53. function getBox(arr, i) { // input Uint8Array, start index
  54. return [toInt(arr, i), toString(arr, i + 4, i + 8)]
  55. }
  56. function getSubBox(arr, box_name) { // input Uint8Array, box name
  57. var i = 0;
  58. res = getBox(arr, i);
  59. main_length = res[0]; name = res[1]; // this boxes length and name
  60. i = i + 8;
  61. var sub_box = null;
  62. while (i < main_length) {
  63. res = getBox(arr, i);
  64. l = res[0]; name = res[1];
  65. if (box_name == name) {
  66. sub_box = arr.slice(i, i + l)
  67. }
  68. i = i + l;
  69. }
  70. return sub_box;
  71. }
  72. function hasFirstSampleFlag(arr) { // input Uint8Array
  73. // [moof [mfhd] [traf [tfhd] [tfdt] [trun]]]
  74. var traf = getSubBox(arr, "traf");
  75. if (traf == null) { return false; }
  76. var trun = getSubBox(traf, "trun");
  77. if (trun == null) { return false; }
  78. // ISO/IEC 14496-12:2012(E) .. pages 5 and 57
  79. // bytes: (size 4), (name 4), (version 1 + tr_flags 3)
  80. var flags = trun.slice(10, 13); // console.log(flags);
  81. f = flags[1] & 4; // console.log(f);
  82. return f == 4;
  83. }
  84. // consider these callbacks:
  85. // - putPacket : called when websocket receives data
  86. // - loadPacket : called when source_buffer is ready for more data
  87. // Both operate on a common fifo
  88. function putPacket(arr) {
  89. // receives ArrayBuffer. Called when websocket gets more data
  90. // first packet ever to arrive: write directly to source_buffer
  91. // source_buffer ready to accept: write directly to source_buffer
  92. // otherwise insert it to queue
  93. var memview = new Uint8Array(arr);
  94. if (verbose) { console.log("got", arr.byteLength, "bytes. Values=", memview[0], memview[1], memview[2], memview[3], memview[4]); }
  95. res = getBox(memview, 0);
  96. main_length = res[0]; name = res[1]; // this boxes length and name
  97. // if ((name == "ftyp") && (pass == 0)) {
  98. // pass = pass + 1;
  99. // console.log("got ftyp");
  100. // }
  101. // else if ((name == "moov") && (pass == 1)) {
  102. // pass = pass + 1;
  103. // console.log("got moov");
  104. // }
  105. // else if ((name == "moof") && (pass == 2)) {
  106. // if (hasFirstSampleFlag(memview)) {
  107. // pass = pass + 1;
  108. // console.log("got that special moof");
  109. // }
  110. // else {
  111. // return;
  112. // }
  113. // }
  114. // else if (pass < 3) {
  115. // return;
  116. // }
  117. // keep the latency to minimum
  118. let latest = stream_live.duration;
  119. if ((stream_live.duration >= buffering_sec) &&
  120. ((latest - stream_live.currentTime) > buffering_sec_seek)) {
  121. console.log("seek from ", stream_live.currentTime, " to ", latest);
  122. df = (stream_live.duration - stream_live.currentTime); // this much away from the last available frame
  123. if ((df > buffering_sec_seek)) {
  124. seek_to = stream_live.duration - buffering_sec_seek_distance;
  125. stream_live.currentTime = seek_to;
  126. }
  127. }
  128. data = arr;
  129. if (!stream_started) {
  130. if (verbose) { console.log("Streaming started: ", memview[0], memview[1], memview[2], memview[3], memview[4]); }
  131. stream_started = true;
  132. source_buffer.appendBuffer(data);
  133. cc = cc + 1;
  134. return;
  135. }
  136. queue.push(data); // add to the end
  137. if (verbose) { console.log("queue push:", queue.length); }
  138. }
  139. function loadPacket() { // called when source_buffer is ready for more
  140. if (!source_buffer.updating) { // really, really ready
  141. if (queue.length > 0) {
  142. inp = queue.shift(); // pop from the beginning
  143. if (verbose) { console.log("queue pop:", queue.length); }
  144. var memview = new Uint8Array(inp);
  145. if (verbose) { console.log(" ==> writing buffer with", memview[0], memview[1], memview[2], memview[3]); }
  146. source_buffer.appendBuffer(inp);
  147. cc = cc + 1;
  148. }
  149. else { // the queue runs empty, so the next packet is fed directly
  150. stream_started = false;
  151. }
  152. }
  153. else { // so it was not?
  154. }
  155. }
  156. function opened() { // MediaSource object is ready to go
  157. // https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/duration
  158. ms.duration = buffering_sec;
  159. source_buffer = ms.addSourceBuffer(codecPars);
  160. // https://developer.mozilla.org/en-US/docs/Web/API/source_buffer/mode
  161. var myMode = source_buffer.mode;
  162. source_buffer.mode = 'sequence';
  163. // source_buffer.mode = 'segments';
  164. source_buffer.addEventListener("updateend", loadPacket);
  165. ws = new WebSocket("ws://127.0.0.1:15555/live.mp4?sim=12345678901&channel=3&token=123456"); //创建WebSocket连接
  166. ws.onmessage = function (e) {
  167. //当客户端收到服务端发来的消息时,触发onmessage事件,参数e.data包含server传递过来的数据
  168. console.log(e.data);
  169. putPacket(e.data);
  170. }
  171. }
  172. function startup() {
  173. ms.addEventListener('sourceopen', opened, false);
  174. // get reference to video
  175. stream_live = document.getElementById('stream_live');
  176. // set mediasource as source of video
  177. stream_live.src = window.URL.createObjectURL(ms);
  178. }
  179. function base64ToArrayBuffer(base64) {
  180. var binary_string = window.atob(base64);
  181. var len = binary_string.length;
  182. var bytes = new Uint8Array(len);
  183. for (var i = 0; i < len; i++) {
  184. bytes[i] = binary_string.charCodeAt(i);
  185. }
  186. return bytes.buffer;
  187. }
  188. window.onload = function () {
  189. startup();
  190. }
  191. </script>
  192. </body>
  193. </html>