OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview |
| 7 * Class implement the video frame recorder extension client. |
| 8 */ |
| 9 |
| 10 'use strict'; |
| 11 |
| 12 /** @suppress {duplicate} */ |
| 13 var remoting = remoting || {}; |
| 14 |
| 15 /** |
| 16 * @constructor |
| 17 * @param {remoting.ClientPlugin} plugin |
| 18 */ |
| 19 remoting.VideoFrameRecorder = function(plugin) { |
| 20 this.fileWriter_ = null; |
| 21 this.isRecording_ = false; |
| 22 this.plugin_ = plugin; |
| 23 }; |
| 24 |
| 25 /** |
| 26 * Starts or stops video recording. |
| 27 */ |
| 28 remoting.VideoFrameRecorder.prototype.startStopRecording = function() { |
| 29 var data = {}; |
| 30 if (this.isRecording_) { |
| 31 this.isRecording_ = false; |
| 32 data = { type: 'stop' } |
| 33 |
| 34 chrome.fileSystem.chooseEntry( |
| 35 {type: 'saveFile', suggestedName: 'videoRecording.pb'}, |
| 36 this.onFileChosen_.bind(this)); |
| 37 } else { |
| 38 this.isRecording_ = true; |
| 39 data = { type: 'start' } |
| 40 } |
| 41 this.plugin_.sendClientMessage('video-recorder', JSON.stringify(data)); |
| 42 } |
| 43 |
| 44 /** |
| 45 * Returns true if the session is currently being recorded. |
| 46 * @return {boolean} |
| 47 */ |
| 48 remoting.VideoFrameRecorder.prototype.isRecording = function() { |
| 49 return this.isRecording_; |
| 50 } |
| 51 |
| 52 /** |
| 53 * Handles 'video-recorder' extension messages and returns true. Returns |
| 54 * false for all other message types. |
| 55 * @param {string} type Type of extension message. |
| 56 * @param {string} data Content of the extension message. |
| 57 * @return {boolean} |
| 58 */ |
| 59 remoting.VideoFrameRecorder.prototype.handleMessage = |
| 60 function(type, data) { |
| 61 if (type != 'video-recorder') { |
| 62 return false; |
| 63 } |
| 64 |
| 65 var message = getJsonObjectFromString(data); |
| 66 var messageType = getStringAttr(message, 'type'); |
| 67 var messageData = getStringAttr(message, 'data'); |
| 68 |
| 69 if (messageType == 'next-frame-reply') { |
| 70 if (!this.fileWriter_) { |
| 71 console.log("Received frame but have no writer"); |
| 72 return true; |
| 73 } |
| 74 if (!messageData) { |
| 75 console.log("Finished receiving frames"); |
| 76 this.fileWriter_ = null; |
| 77 return true; |
| 78 } |
| 79 |
| 80 console.log("Received frame"); |
| 81 /* jscompile gets confused if you refer to this as just atob(). */ |
| 82 var videoPacketString = /** @type {string?} */ window.atob(messageData); |
| 83 |
| 84 console.log("Converted from Base64 - length:" + videoPacketString.length); |
| 85 var byteArrays = []; |
| 86 |
| 87 for (var offset = 0; offset < videoPacketString.length; offset += 512) { |
| 88 var slice = videoPacketString.slice(offset, offset + 512); |
| 89 var byteNumbers = new Array(slice.length); |
| 90 for (var i = 0; i < slice.length; i++) { |
| 91 byteNumbers[i] = slice.charCodeAt(i); |
| 92 } |
| 93 var byteArray = new Uint8Array(byteNumbers); |
| 94 byteArrays.push(byteArray); |
| 95 } |
| 96 |
| 97 console.log("Writing frame"); |
| 98 videoPacketString = null; |
| 99 /** |
| 100 * Our current compiler toolchain only understands the old (deprecated) |
| 101 * Blob constructor, which does not accept any parameters. |
| 102 * TODO(wez): Remove this when compiler is updated (see crbug.com/405298). |
| 103 * @suppress {checkTypes} |
| 104 * @param {Array} parts |
| 105 * @return {Blob} |
| 106 */ |
| 107 var makeBlob = function(parts) { |
| 108 return new Blob(parts); |
| 109 } |
| 110 var videoPacketBlob = makeBlob(byteArrays); |
| 111 byteArrays = null; |
| 112 |
| 113 this.fileWriter_.write(videoPacketBlob); |
| 114 |
| 115 return true; |
| 116 } |
| 117 |
| 118 console.log("Unrecognized message: " + messageType); |
| 119 return true; |
| 120 } |
| 121 |
| 122 /** @param {FileEntry} fileEntry */ |
| 123 remoting.VideoFrameRecorder.prototype.onFileChosen_ = function(fileEntry) { |
| 124 if (!fileEntry) { |
| 125 console.log("Cancelled save of video frames."); |
| 126 } else { |
| 127 /** @type {function(string):void} */ |
| 128 chrome.fileSystem.getDisplayPath(fileEntry, function(path) { |
| 129 console.log("Saving video frames to:" + path); |
| 130 }); |
| 131 fileEntry.createWriter(this.onFileWriter_.bind(this)); |
| 132 } |
| 133 } |
| 134 |
| 135 /** @param {FileWriter} fileWriter */ |
| 136 remoting.VideoFrameRecorder.prototype.onFileWriter_ = function(fileWriter) { |
| 137 console.log("Obtained FileWriter for video frame write"); |
| 138 fileWriter.onwriteend = this.onWriteComplete_.bind(this); |
| 139 this.fileWriter_ = fileWriter; |
| 140 this.fetchNextFrame_(); |
| 141 } |
| 142 |
| 143 remoting.VideoFrameRecorder.prototype.onWriteComplete_ = function(e) { |
| 144 console.log("Video frame write complete"); |
| 145 this.fetchNextFrame_(); |
| 146 } |
| 147 |
| 148 remoting.VideoFrameRecorder.prototype.fetchNextFrame_ = function() { |
| 149 console.log("Request next video frame"); |
| 150 var data = { type: 'next-frame' } |
| 151 this.plugin_.sendClientMessage('video-recorder', JSON.stringify(data)); |
| 152 } |
OLD | NEW |