こんにちは@mettoboshiです。Cocos2d-x Advent Calendar 2015の5日目を担当させて頂きます。よろしくお願いします。今回は動画共有サービスであるEveryplayの導入と録画を実行するまでを書きたいと思います。
※今回作成したサンプルは以下にもあがっています
https://github.com/mettoboshi/everyplay-cocos2d-x
使用したライブラリのバージョンなど
- Cocos2d-x v3.9
- everyplay-ios-sdk v2.0.1
- everyplay-android-sdk v1.5.1
Everyplayとは
Everyplay( https://everyplay.com/feed )は動画共有サービスです。
アプリにSDKを組み込むことで簡単にプレイ動画を録画したりシェアすることが可能です。
Everyplayは2014年にUnity社に買収されておりUnityで使うイメージがありますが、iOSやAndroid用のSDKが用意されているので、Cocos2d-xでも使用することが可能です。
他にも、Lobi REC SDK(https://lobi.co/recsdk) や Kamcord(https://www.kamcord.com/) などがありますが、Kamcordから今年の9月末にサポート終了の案内がでるなど動画共有サービスにおいても大きな変化があった一年になった気がします。
現状では、ユーザーが多いサービスを選択するのが今のところベターな気がしています。
実際の使用例
Braindots(http://translimit.co.jp/services/braindots.html) はCocos2d-xで作成されており、Everyplayを導入しています。
具体的には以下のように結果画面でリプレイのサムネイルを表示し、リプレイボタンを押した先で動画の再生/シェアができる部分がEveryplayを用いて実現されています。
このように、動画を録画するだけでなく、自分のプレイをわかりやすく表示したり、リプレイを見られるようにするという用途でもEveryplayは有効に使えることがわかると思います。
前置きはこれくらいにして、早速導入してみましょう。
ダウンロード
以下のURLからSDKをダウンロードできます。
URL : https://developers.everyplay.com/download
「iOSカスタムエンジン(everyplay-ios-sdk-master.zip)」と「Androidカスタムエンジン(everyplay-android-sdk-master.zip)」をダウンロードします。
インストール
ドキュメントは以下が参考になります。
EVERYPLAYを、IOSゲームへインテグレート
(https://developers.everyplay.com/documentation/Everyplay-integration-to-iOS-game.md)
ちなみに、Cocos2dに関するドキュメント(https://developers.everyplay.com/documentation/Everyplay-integration-to-Cocos2d-game.md) もあり、この中でcocos2d-xに関する記載もあるのですが、リポジトリが3年前だったのでそのままでは使えませんでした。(参考になる可能性はあります・・)
では気を取り直してインストールを続けましょう。
iOSの場合
- Everyplay.frameworkとEveryplay.bundleの配置
ダウンロードしてきた、everyplay-ios-sdk-master.zipを解凍すると中にEveryplay.bundleとEveryplay.frameworkというファイルがあるので、これをプロジェクトに追加していきましょう。今回は、proj.ios_mac/配下に、Frameworks/Everyplayというフォルダを作成し、そこにコピーしました。
次に、XcodeのプロジェクトのFrameworks直下にドラッグ&ドロップで上記2ファイルを追加します。
- フレームワークの追加
次は、Everyplayが使用するフレームワークを追加していきます。Cocos2d-xですでに使っているものもあるので、使用するのは以下の11個です。
AdSupport, AssetsLibrary, CoreImage, CoreMedia, CoreVideo, MessageUI, MobileCoreServices, Social, StoreKit, SystemConfiguration, Twitter
- コードの追加
今回は、AppController.hとAppController.mmに直接コードをdelegateを追加し、メソッドを追加しました。
#import <UIKit/UIKit.h>
#import <Everyplay/Everyplay.h> // add
@class RootViewController;
// add EveryplayDelegate
@interface AppController : NSObject <EveryplayDelegate, UIApplicationDelegate> {
UIWindow *window;
}
@property(nonatomic, readonly) RootViewController* viewController;
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//・・・中略
app->run();
[Everyplay setClientId:@"f77b511414beb1ea7d97762cdc5849e2d2dd27d1" clientSecret:@"2260808cef426ac09037a6d69f4d073e67b380a9" redirectURI:@"https://m.everyplay.com/auth"];
[Everyplay initWithDelegate:self andParentViewController:_viewController];
[[[Everyplay sharedInstance] capture] autoRecordForSeconds:5 withDelay:1];
return YES;
}
}
- (void)everyplayShown
{
NSLog(@"everyplayshown");
cocos2d::Director::getInstance()->pause();
}
- (void)everyplayHidden
{
NSLog(@"everyplayHidden");
cocos2d::Director::getInstance()->resume();
}
- (void)everyplayRecordingStopped
{
NSLog(@"everyplayRecordingStopped");
[[Everyplay sharedInstance] playLastRecording];
}
上記コードを追加し、実機で実行すると5秒後にEveryplayのリプレイ画面が表示されるはずです。
この画面の左下の再生ボタンを押下すると動画の再生、右上のボタンを押すとシェアができます。
また、今回はEveryplayの初期化でclientIdとclientSecretを設定していますが、これは公式のドキュメントに記載されているものなので、実際に使う場合はユーザ登録をしてアプリを作成しそのIDを使用しましょう。
では次にAndroidでも録画が実行できるようにしていきます。
Androidの場合
- SDKのコピー
ダウンロードしてきた、everyplay-android-sdk-master.zipを解凍すると中にeveryplay-androidフォルダが作成されるので、proj.android配下にFrameworksフォルダを作成しコピーします。(everyplay-androidをEveryplayにリネームしていますが、これはiOSと合わせただけなので必須ではないです)
- project.propertiesの編集
ここからはEclipseの作業になります。
先ほどコピーしたEveryplayのSDKをproject.propertiesに追加します。
# add
android.library.reference.2=Frameworks/everyplay-android
jni/Application.mkを編集します。Everyplayではarmabiがないため、単純にコンパイルするとエラーになってしまうためです。
# add
APP_ABI := armeabi-v7a x86
proj.android/AndroidManifest.xmlにEveryplayで使用しているActivityを追加します。
30行目くらいのactivityが閉じたところの次に以下を追加します。
<activity android:name="com.everyplay.Everyplay.view.EveryplaySocialActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="sensor"
android:hardwareAccelerated="true" />
<activity android:name="com.everyplay.Everyplay.view.EveryplayTextInputActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="stateVisible|adjustResize"
android:screenOrientation="sensor"
android:hardwareAccelerated="false" />
<activity android:name="com.everyplay.Everyplay.view.videoplayer.EveryplayVideoPlayerActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="sensor"
android:hardwareAccelerated="true" />
<activity android:name="com.everyplay.Everyplay.view.videoplayer.EveryplayVideoEditorActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="sensor"
android:hardwareAccelerated="true" />
<activity android:name="com.everyplay.Everyplay.view.EveryplaySharingModalActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@style/EveryplaySharingModal"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="sensor"
android:fitsSystemWindows="true"
android:hardwareAccelerated="true" />
<activity android:name="com.everyplay.Everyplay.view.browser.EveryplayBrowserActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="sensor"
android:hardwareAccelerated="false" />
<activity android:name="com.everyplay.Everyplay.view.auth.EveryplayAuthActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.NoTitleBar"
android:screenOrientation="sensor"
android:hardwareAccelerated="false"
android:windowSoftInputMode="adjustResize" />
<activity android:name="com.everyplay.Everyplay.view.auth.EveryplayAddConnectionActivity"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.Dialog"
android:hardwareAccelerated="false"
android:screenOrientation="sensor"
android:windowSoftInputMode="adjustResize" />
<activity android:name="com.everyplay.Everyplay.communication.socialnetworks.EveryplayFacebook"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.Dialog"
android:hardwareAccelerated="false"
android:screenOrientation="sensor"
android:windowSoftInputMode="adjustResize" />
<service android:name="com.everyplay.Everyplay.communication.upload.EveryplayUploadService" />
一番最後のパーミッションの定義のところに以下を追加します。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
これでAndroidのビルドは通るようになるはずです。
以下のコマンドでビルドがとおることを確認しておいてください。
cocos run -p android
- 録画の実装
次はiOSと同じく自動的に録画をして結果を出せるようにしてみましょう。
今回はsrc/org/cocos2dx/cpp/AppActivityにまるっと書いてしまいましたが、AppActivityを汚すのは良くないので、ちゃんと作るときはEveryplayの機能は、EveryplayManager.javaのように別ファイルに切り出して、Cocos2d-xからJNIで呼び出すようにするとよいでしょう。
package org.cocos2dx.cpp;
import org.cocos2dx.lib.Cocos2dxActivity;
import com.everyplay.Everyplay.Everyplay;
import com.everyplay.Everyplay.IEveryplayListener;
import android.os.Bundle;
public class AppActivity extends Cocos2dxActivity implements IEveryplayListener {
private static final String TAG = "EveryplayRecord";
private static String CLIENT_ID = "f77b511414beb1ea7d97762cdc5849e2d2dd27d1";
private static String CLIENT_SECRET = "2260808cef426ac09037a6d69f4d073e67b380a9";
private static String REDIRECT_URI = "https://m.everyplay.com/auth";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setup();
}
public void setup() {
Everyplay.configureEveryplay(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);
Everyplay.initEveryplay(this, this);
new Thread(new Runnable(){
@Override
public void run()
{
try
{
Thread.sleep(20000);
Everyplay.startRecording();
Thread.sleep(10000);
Everyplay.stopRecording();
Everyplay.playLastRecording();
}
catch( InterruptedException e )
{
e.printStackTrace();
}
}
}).start();
}
@Override
public void onEveryplayReadyForRecording(int enabled) {
}
@Override
public void onEveryplayRecordingStarted() {
}
@Override
public void onEveryplayRecordingStopped() {
}
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
public void onEveryplayHidden() {
}
@Override
public void onEveryplayFaceCamSessionStarted() {
}
@Override
public void onEveryplayFaceCamRecordingPermission(int granted) {
}
@Override
public void onEveryplayShown() {
}
@Override
public void onEveryplayFaceCamSessionStopped() {
}
@Override
public void onEveryplayUploadDidStart(int videoId) {
}
@Override
public void onEveryplayUploadDidProgress(int videoId, double progress) {
}
@Override
public void onEveryplayUploadDidComplete(int videoId) {
}
@Override
public void onEveryplayThumbnailReadyAtTextureId(int textureId,
int portraitMode) {
}
@Override
public void onEveryplayAccountDidChange() {
}
}
さて、これで自動で録画してリプレイを表示してくれるようになったはずです。
セットアップと同時にSleepしながら実行しているメソッドが録画、停止、再生になります。
// 録画開始
Everyplay.startRecording();
// 録画停止
Everyplay.stopRecording();
// 最後に録画したリプレイを見る
Everyplay.playLastRecording();
あえてSleepを入れているのは、Androidの場合、setup後にonEveryplayReadyForRecordingのコールバックが返ってくるまで録画ができないのですが、このコールバックが返戻されるまでそれなりに時間がかかるからです。実際にアプリに組み込む際はこの辺も意識する必要があります。
無事、Everyplayでリプレイが見られるようになりました。
おわりに
今回はEveryplayの導入について紹介しました。
しかし、今日の実装ではアプリに組み込めないためこの後CocosからiOS/Android両方で使えるようにしたり、綺麗に分離したりする必要があります。
Everyplayには、録画・停止・再生以外にも一時停止/再開はもちろん、FaceCamで自分の顔や声を取りながらの録画、サムネイルを取得、メタデータを設定しておいて後でEveryplayのサービスAPIを使ってデータを取得できるようにすることなどまだ色々とできることがあります。
また、Everyplayはハマりどころがとてつもなく多く、録画できるようになってからも色々と苦労する点がありました。もし需要がありそうならその辺もまとめたいと思います。
ちなみにEveryplayで検索すると、さくっとプレイ動画が撮影できたみたいな記事がみつかりますが、これはだいたいUnityでやっている記事だと思います。Cocosでやると情報がめっちゃ少ないので結構辛い道のりになります。
Everyplayを使ってみたいCocosユーザの方にこの記事が少しでも足しになれば幸いです。(いるかな・・)
明日は、@kohashiさんの CocosStudioとカスタムクラス・カスタムアクションになるようです。CocosStudio使った開発に関する情報、楽しみですね。
では。