| Index: remoting/webapp/video_frame_recorder.js
|
| diff --git a/remoting/webapp/video_frame_recorder.js b/remoting/webapp/video_frame_recorder.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..67301622c9cbe146c704838f80c5d156d22cec0e
|
| --- /dev/null
|
| +++ b/remoting/webapp/video_frame_recorder.js
|
| @@ -0,0 +1,152 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * @fileoverview
|
| + * Class implement the video frame recorder extension client.
|
| + */
|
| +
|
| +'use strict';
|
| +
|
| +/** @suppress {duplicate} */
|
| +var remoting = remoting || {};
|
| +
|
| +/**
|
| + * @constructor
|
| + * @param {remoting.ClientPlugin} plugin
|
| + */
|
| +remoting.VideoFrameRecorder = function(plugin) {
|
| + this.fileWriter_ = null;
|
| + this.isRecording_ = false;
|
| + this.plugin_ = plugin;
|
| +};
|
| +
|
| +/**
|
| + * Starts or stops video recording.
|
| + */
|
| +remoting.VideoFrameRecorder.prototype.startStopRecording = function() {
|
| + var data = {};
|
| + if (this.isRecording_) {
|
| + this.isRecording_ = false;
|
| + data = { type: 'stop' }
|
| +
|
| + chrome.fileSystem.chooseEntry(
|
| + {type: 'saveFile', suggestedName: 'videoRecording.pb'},
|
| + this.onFileChosen_.bind(this));
|
| + } else {
|
| + this.isRecording_ = true;
|
| + data = { type: 'start' }
|
| + }
|
| + this.plugin_.sendClientMessage('video-recorder', JSON.stringify(data));
|
| +}
|
| +
|
| +/**
|
| + * Returns true if the session is currently being recorded.
|
| + * @return {boolean}
|
| + */
|
| +remoting.VideoFrameRecorder.prototype.isRecording = function() {
|
| + return this.isRecording_;
|
| +}
|
| +
|
| +/**
|
| + * Handles 'video-recorder' extension messages and returns true. Returns
|
| + * false for all other message types.
|
| + * @param {string} type Type of extension message.
|
| + * @param {string} data Content of the extension message.
|
| + * @return {boolean}
|
| + */
|
| +remoting.VideoFrameRecorder.prototype.handleMessage =
|
| + function(type, data) {
|
| + if (type != 'video-recorder') {
|
| + return false;
|
| + }
|
| +
|
| + var message = getJsonObjectFromString(data);
|
| + var messageType = getStringAttr(message, 'type');
|
| + var messageData = getStringAttr(message, 'data');
|
| +
|
| + if (messageType == 'next-frame-reply') {
|
| + if (!this.fileWriter_) {
|
| + console.log("Received frame but have no writer");
|
| + return true;
|
| + }
|
| + if (!messageData) {
|
| + console.log("Finished receiving frames");
|
| + this.fileWriter_ = null;
|
| + return true;
|
| + }
|
| +
|
| + console.log("Received frame");
|
| + /* jscompile gets confused if you refer to this as just atob(). */
|
| + var videoPacketString = /** @type {string?} */ window.atob(messageData);
|
| +
|
| + console.log("Converted from Base64 - length:" + videoPacketString.length);
|
| + var byteArrays = [];
|
| +
|
| + for (var offset = 0; offset < videoPacketString.length; offset += 512) {
|
| + var slice = videoPacketString.slice(offset, offset + 512);
|
| + var byteNumbers = new Array(slice.length);
|
| + for (var i = 0; i < slice.length; i++) {
|
| + byteNumbers[i] = slice.charCodeAt(i);
|
| + }
|
| + var byteArray = new Uint8Array(byteNumbers);
|
| + byteArrays.push(byteArray);
|
| + }
|
| +
|
| + console.log("Writing frame");
|
| + videoPacketString = null;
|
| + /**
|
| + * Our current compiler toolchain only understands the old (deprecated)
|
| + * Blob constructor, which does not accept any parameters.
|
| + * TODO(wez): Remove this when compiler is updated (see crbug.com/405298).
|
| + * @suppress {checkTypes}
|
| + * @param {Array} parts
|
| + * @return {Blob}
|
| + */
|
| + var makeBlob = function(parts) {
|
| + return new Blob(parts);
|
| + }
|
| + var videoPacketBlob = makeBlob(byteArrays);
|
| + byteArrays = null;
|
| +
|
| + this.fileWriter_.write(videoPacketBlob);
|
| +
|
| + return true;
|
| + }
|
| +
|
| + console.log("Unrecognized message: " + messageType);
|
| + return true;
|
| +}
|
| +
|
| +/** @param {FileEntry} fileEntry */
|
| +remoting.VideoFrameRecorder.prototype.onFileChosen_ = function(fileEntry) {
|
| + if (!fileEntry) {
|
| + console.log("Cancelled save of video frames.");
|
| + } else {
|
| + /** @type {function(string):void} */
|
| + chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
|
| + console.log("Saving video frames to:" + path);
|
| + });
|
| + fileEntry.createWriter(this.onFileWriter_.bind(this));
|
| + }
|
| +}
|
| +
|
| +/** @param {FileWriter} fileWriter */
|
| +remoting.VideoFrameRecorder.prototype.onFileWriter_ = function(fileWriter) {
|
| + console.log("Obtained FileWriter for video frame write");
|
| + fileWriter.onwriteend = this.onWriteComplete_.bind(this);
|
| + this.fileWriter_ = fileWriter;
|
| + this.fetchNextFrame_();
|
| +}
|
| +
|
| +remoting.VideoFrameRecorder.prototype.onWriteComplete_ = function(e) {
|
| + console.log("Video frame write complete");
|
| + this.fetchNextFrame_();
|
| +}
|
| +
|
| +remoting.VideoFrameRecorder.prototype.fetchNextFrame_ = function() {
|
| + console.log("Request next video frame");
|
| + var data = { type: 'next-frame' }
|
| + this.plugin_.sendClientMessage('video-recorder', JSON.stringify(data));
|
| +}
|
|
|