はじめに

アメリカのシリコンバレーに拠点を置くTIS Ventures, Inc.(以降TVI)の井上です。
自炊でカレーばかり作るので、あだ名がカレーになりました。 フロントエンドが好きなソフトウェアエンジニアです。

TVIでは、新規事業創出を目的とし、シリコンバレー界隈の技術トレンドのキャッチアップ、スタートアップ企業のテックハントなどを行っております。

この度、10月にサンノゼで行われたカンファレンス「API World」のハッカソンに参加しました。本記事は、その参加レポートです。

※TVIはDev.toでブログを公開しています。本記事の英語版もありますので、興味のある方は是非、以下をご覧ください!

API World Hackathon Report No.1 – How to record a web-camera video in React – DEV Community 👩‍💻👨‍💻

API Worldとは

公式ページURL: https://apiworld.co/

API Worldは、世界最大のAPIに関するカンファレンスです。セッション、企業ブースの他にも、ハッカソンが開催されます。ハッカソンは総勢100人以上が参加し、2日間にわたって開催される大規模なものです。

チームとハッカソンの結果

ハッカソンは、最初にチームメンバーを探さないといけないのですが、 私は運良く、フロントエンドエンジニアとバックエンドエンジニア、アイディアマンが揃っている、バランスの良いチームに入れてもらえました。

  • チームメンバーとの集合写真 

私たちが作ったプロジェクトは、興味深いコミュニケーション・アプリケーションとしてRing Centralチャレンジの最優秀賞に選ばれ、さらに全チームのトップ5に選出されました。

以下の動画はトップ5に選ばれて登壇した時の様子です。(ムービーは載せられないので8倍速にしてgif化してます) デモの担当だったのですが、スピーカーが話しすぎたために出番はカットとなりました・・・ かわりに、微動だにしない私のスタンディング技術にご注目ください!(右から3番目が私です)

何を作ったか

CMを見ているユーザーが、CMに興味があるかどうかを判定するソリューションです。 クライアント側、バックエンド側をチームで手分けして作りました。 以下デモページ(CM動画一覧)です。

デモページ

  • クライアント側:CM再生開始・視聴者の表情撮影
    • 視聴者がCMサムネイル画像をクリックすると、モーダルウィンドウが表示され、CMが再生されます。それと同時に、Webカメラによる録画が開始され、CMを見ているユーザーの表情がウェブカメラで撮影されます。撮影した動画はAmazon S3に送られます。
  • バックエンド側:動画解析・蓄積
    • Amazon S3に送られた動画は、Amazon Rekognitionで動画中の視聴者の表情を解析します。解析結果は蓄積され、APIで公開されます。

使っている技術スタックは以下の通りです。

私は以下のフロントエンドの実施を担当しました。

  • デモページ(CM動画一覧)
  • Webカメラ録画機能

詳細については、DevPostの以下のページをご覧ください。

Reactでウェブカメラ動画を撮影する方法

RecordRTCを使えば簡単に実装できます。簡単な例を以下に示します。

import React from 'react';
import RecordRTC from 'recordrtc';

class CameraRecorder extends React.Component {
  constructor(props) {
    super(props);
    this.state = { recordVideo: null };

    this.requestUserMedia = this.requestUserMedia.bind(this);
    this.startRecord = this.startRecord.bind(this);
    this.stopRecord = this.stopRecord.bind(this);
    this.getUserMedia = this.getUserMedia.bind(this);
  }

  requestUserMedia() {
    this.getUserMedia(stream => {
      this.setState({ src: window.URL.createObjectURL(stream) });
    });
  }

  startRecord() {
    this.getUserMedia(stream => {
      this.state.recordVideo = RecordRTC(stream, { type: 'video' });
      this.state.recordVideo.startRecording();
    });
  }

  stopRecord() {
    this.state.recordVideo.stopRecording(() => {
      this.state.recordVideo.save();
    });
  }

  getUserMedia(callback) {
    navigator.getUserMedia({ audio: false, video: true }, callback, error => alert(JSON.stringify(error)));
  }

  render() {
    return (
      <div>
        <button onClick={this.startRecord}>Start Record</button>
        <button onClick={this.stopRecord}>Stop Record</button>
      </div>
    )
  }
}

export default CameraRecorder;

おわりに

日米を通じて人生初のハッカソンでしたが、チームメンバーに恵まれたおかげでTOP5に選出されました。
はじめて会う人とチームを組んで開発を進める中で、アイディアを形にする喜びを実感できたのは貴重な体験です。
また英語がカタコトでもボディランゲージとソースコードを介したコミュニケーションでなんとか乗り切れることもわかりました。
今後もハッカソンには継続的に参加していく予定です。

いろんなエンジニアの方々と交流を楽しみながら、実績を残していければと考えています。


本コンテンツはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。