ビデオキャプチャデバイスの管理は、Real-Time Communication (RTC) のコア機能です。ARTC SDK では、デバイス管理を実現する豊富な API が提供されています。ただし、各プラットフォームにおける実装は大きく異なるため、本トピックでは、RTC エンジンが提供するビデオデバイス管理機能について説明します。
機能概要
ARTC SDK は、開発者に対してビデオキャプチャデバイスに対する包括的な制御機能を提供します。iOS や Android などのプラットフォームにおいて、ズーム、露出、手動/自動フォーカスモードといったカメラパラメーターを細かく調整することで、ビデオキャプチャ品質を大幅に向上させることができます。
サンプルコード
Android 向けビデオキャプチャデバイス管理:Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/CameraCommonControl/CameraActivity.java。
iOS 向けビデオキャプチャデバイス管理:iOS/ARTCExample/BasicUsage/CameraCommonSetting/CameraCommonControlVC.swift。
Harmony 向けビデオキャプチャデバイス管理:Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/CameraPage.ets。
前提条件
Alibaba Cloud アカウント(root ユーザー)を保有し、Real-Time Communication (RTC) アプリケーションを作成済みである必要があります。詳細については、「アプリケーションの作成」をご参照ください。また、ApsaraVideo Live コンソールより AppID および AppKey を取得済みである必要があります。
SDK の統合および基本機能の実装:
ARTC SDK をプロジェクトに統合し、基本的な Real-Time Communication (RTC) 機能を実装済みである必要があります。詳細については、「SDK の統合」および「音声・映像通話の実装」をご参照ください。
たとえば
startPreviewでプレビューを開始したり、joinChannelでチャンネルに参加したりして、カメラが起動されている状態です。
実装方法
カメラズームの設定
ARTC SDK を使用すると、カメラズームを制御できます。
API リファレンス
/**
* @brief カメラズームを設定します。
* @param zoom ズーム係数。値の範囲は 1 からカメラがサポートする最大ズーム値までです。
* @return
* - 0:成功。
* - 0 以外の値:失敗。
* @note この API は iOS および Android のみで利用可能です。
*/
public abstract int setCameraZoom(float zoom);
/**
* @brief カメラの最大ズーム係数を取得します。
* @return カメラの最大ズーム係数。
*/
public abstract float GetCameraMaxZoomFactor();
/**
* @brief カメラの現在のズーム係数を取得します。
* @return カメラの現在のズーム係数。
*/
public abstract float GetCurrentZoom();サンプル
Android
// ズーム情報を取得します。
private void initZoomSeekBar() {
if (mAliRtcEngine != null) {
zoomSeekBar.setEnabled(true);
// 最大ズーム値を取得します。
float maxZoom = mAliRtcEngine.GetCameraMaxZoomFactor();
float currZoom = mAliRtcEngine.GetCurrentZoom();
// SeekBar の範囲を設定します(1.0 ~ maxZoom、ステップ幅 0.1)。
if(maxZoom >= 1.0) {
int maxProgress = (int)((maxZoom - 1) * 10);
zoomSeekBar.setMax(maxProgress);
int currProgress = (int)((currZoom - 1) * 10);
zoomSeekBar.setProgress(currProgress);
} else{
zoomSeekBar.setEnabled(false);
}
}
}
// ズームを設定します。
zoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(mAliRtcEngine != null) {
float newZoom = (float)((i+10) / 10.0);
mAliRtcEngine.setCameraZoom(newZoom);
zoomTextView.setText(String.format("%.1f", newZoom));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});iOS
// ズーム情報を取得します。
self.cameraZoomSlider.isEnabled = true
let maxZoom = rtcEngine.getCameraMaxZoomFactor()
let currZoom = rtcEngine.getCurrentZoom()
"Get maxZoom=\(maxZoom), currZoom=\(currZoom)".printLog()
self.cameraZoomSlider.minimumValue = 1.0
if maxZoom > 1.0 {
self.cameraZoomSlider.maximumValue = maxZoom
} else {
self.cameraZoomSlider.isEnabled = false
}
if currZoom >= 1.0 && currZoom <= maxZoom {
self.cameraZoomSlider.value = currZoom
self.cameraZoomValueLabel.text = String(format: "%.1f", self.cameraZoomSlider.value)
}
else {
self.cameraZoomSlider.value = self.cameraZoomSlider.minimumValue
self.cameraZoomValueLabel.text = "\(self.cameraZoomSlider.minimumValue)"
}
// ズームを設定します。
@IBOutlet weak var cameraZoomSlider: UISlider!
@IBOutlet weak var cameraZoomValueLabel: UILabel!
@IBAction func onCameraZoomChanged(_ sender: UISlider) {
let currValue = sender.value
self.cameraZoomValueLabel.text = String(format: "%.1f", currValue)
self.rtcEngine?.setCameraZoom(currValue)
}Harmony
private handleZoomChange(value: number): void {
if (!this.rtcEngine) {
return;
}
// 進捗値に基づいてズーム値を計算:zoom = 1.0 + (value / 10.0)。
const newZoom = 1.0 + (value / 10.0);
// ズーム値を 1.0 ~ 10.0 の範囲にクランプします。
const clampedZoom = Math.max(1.0, Math.min(10.0, newZoom));
this.rtcEngine.setCameraZoom(clampedZoom);
this.zoomValue = clampedZoom.toFixed(1);
console.info(`Set zoom: ${clampedZoom}`);
}カメラ露出の設定
ARTC SDK を使用すると、カメラ露出を設定して画像の輝度を制御できます。
API リファレンス
/**
* @brief カメラ露出を設定します。
* @param exposure 露出値。
* @return
* - 0:成功。
* - 0 以外の値:失敗。
*/
public abstract int SetExposure(float exposure);
/**
* @brief 現在のカメラ露出を取得します。
* @return 現在のカメラ露出。
*/
public abstract float GetCurrentExposure();
/**
* @brief カメラの最小露出を取得します。
* @return カメラの最小露出。
*/
public abstract float GetMinExposure();
/**
* @brief カメラの最大露出を取得します。
* @return カメラの最大露出。
*/
public abstract float GetMaxExposure();サンプル
Android
// 露出情報を取得します。
private void initExposureSeekBar() {
if (mAliRtcEngine != null) {
exposureSeekBar.setEnabled(true);
// 最大露出値を取得します。
float maxExposure = mAliRtcEngine.GetMaxExposure();
// 最小露出値を取得します。
float minExposure = mAliRtcEngine.GetMinExposure();
float currExposure = mAliRtcEngine.GetCurrentExposure();
if(maxExposure > minExposure) {
// SeekBar の範囲をリセットします。
int maxProgress = (int)((maxExposure - minExposure) * 10);
exposureSeekBar.setMax(maxProgress);
int currProgress = (int)((currExposure - minExposure) * 10);
exposureSeekBar.setProgress(currProgress);
} else {
exposureSeekBar.setEnabled(false);
}
}
}
// 露出を設定します。
exposureSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(mAliRtcEngine != null) {
float minExposure = mAliRtcEngine.GetMinExposure();
float newExposure = minExposure + (float)(i / 10.0);
mAliRtcEngine.SetExposure(newExposure);
exposureTextView.setText(String.format("% .1f", newExposure));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});iOS
// デバイスの露出情報を取得します。
self.cameraExposureSlider.isEnabled = true
let minExposure = rtcEngine.getMinExposure()
let maxExposure = rtcEngine.getMaxExposure()
let currExposure = rtcEngine.getCurrentExposure()
"Get minExposure=\(minExposure), maxExposure=\(maxExposure), currExposure=\(currExposure)".printLog()
if maxExposure > minExposure {
self.cameraExposureSlider.minimumValue = minExposure
self.cameraExposureSlider.maximumValue = maxExposure
} else {
self.cameraExposureSlider.isEnabled = false
}
if currExposure >= minExposure && currExposure <= maxExposure {
self.cameraExposureSlider.value = currExposure
self.cameraExposureValueLabel.text = String(format: "%.1f", self.cameraExposureSlider.value)
}
else {
self.cameraExposureSlider.value = self.cameraExposureSlider.minimumValue
self.cameraExposureValueLabel.text = "\(self.cameraExposureSlider.minimumValue)"
}
// 露出を設定します。
@IBOutlet weak var cameraExposureValueLabel: UILabel!
@IBOutlet weak var cameraExposureSlider: UISlider!
@IBAction func onCameraExposureChanged(_ sender: UISlider) {
let currValue = sender.value
self.cameraExposureValueLabel.text = String(format: "%.1f", currValue)
self.rtcEngine?.setExposure(currValue)
}Harmony
// 露出変更を処理します。
private handleExposureChange(value: number): void {
if (!this.rtcEngine) {
return;
}
// 変換式:露出値 = 進捗値 / 10。
const actualValue = value / 10.0;
// 露出値を -12.0 ~ 12.0 の範囲にクランプします。
const clampedExposure = Math.max(-12.0, Math.min(12.0, actualValue));
// ステートを更新します。
this.exposureSliderValue = value;
this.exposureValue = this.formatExposureValue(clampedExposure);
// RTC エンジンを呼び出して露出補正を設定します。
try {
this.rtcEngine.setExposure(clampedExposure);
console.info(`Set exposure compensation: ${clampedExposure}`);
} catch (error) {
console.error('Failed to set exposure compensation:', error);
}
}露出ポイントの手動設定
ARTC SDK を使用すると、露出ポイントを手動で設定できます。ユーザーが画面の任意の位置をタップすると、その領域の照明条件に基づいてカメラの露出が調整されます。
露出ポイントを設定する場合、まず
isCameraExposurePointSupportedインターフェイスを呼び出して、対応を確認する必要があります。座標は正規化された値(0 ~ 1 の範囲)で指定する必要があります。
API リファレンス
/**
* @brief カメラが手動露出ポイントの設定をサポートしているかどうかを確認します。
* @return
* - true:対応。
* - false:非対応。
* @note この API は iOS および Android のみで利用可能であり、現在のカメラで露出ポイントの設定が可能なことを確認するために使用されます。
*/
public abstract boolean isCameraExposurePointSupported();
/**
* @brief カメラの露出ポイントを設定します。
* @param x 正規化された X 座標。値の範囲は 0 ~ 1 です。
* @param y 正規化された Y 座標。値の範囲は 0 ~ 1 です。
* @return
* - 0:成功。
* - 0 以外の値:失敗。
* @note この API は iOS および Android のみで利用可能です。このメソッドを呼び出した後、カメラは指定されたポイントで一度だけ露出調整を行い、その後その露出値を維持します。
*/
public abstract int setCameraExposurePoint(float x, float y);サンプル
Android
// 露出ポイントを手動で設定します。
mLocalViewGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
// ダブルタップを処理します。
// ...
return true;
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
// シングルタップを処理します。
if(mAliRtcEngine != null && mAliRtcEngine.isCameraExposurePointSupported()) {
float[] normalizedCoords = getNormalizedCoordinates(e.getX(), e.getY());
if (normalizedCoords[0] != -1 && normalizedCoords[1] != -1) {
mAliRtcEngine.setCameraExposurePoint(normalizedCoords[0], normalizedCoords[1]);
mCameraExposurePointX.setText(String.format("%.2f", normalizedCoords[0]));
mCameraExposurePointY.setText(String.format("%.2f", normalizedCoords[1]));
}
}
return true;
}
});iOS
@objc func handleSeatViewTap(_ gesture: UITapGestureRecognizer) {
guard let localSeatView = self.localPreviewSeatView else {
return
}
guard let rtcEngine = self.rtcEngine, rtcEngine.isCameraExposurePointSupported() else { return }
let tapPoint = gesture.location(in: localSeatView)
// タップ座標をビデオフレームの正規化座標(0 ~ 1 の範囲)に変換します。
let normalizedX = tapPoint.x / localSeatView.bounds.width
let normalizedY = tapPoint.y / localSeatView.bounds.height
rtcEngine.setCameraExposurePoint(CGPoint(x: normalizedX, y: normalizedY))
self.cameraExposurePointXTextField.text = String(format: "%.2f", normalizedX)
self.cameraExposurePointYTextField.text = String(format: "%.2f", normalizedY)
}Harmony
private handleSingleTap(touchX: number, touchY: number): void {
if (!this.rtcEngine) {
return;
}
// 正規化された座標を取得します。
const normalizedCoords = this.getNormalizedCoordinates(touchX, touchY);
if (normalizedCoords[0] !== -1 && normalizedCoords[1] !== -1) {
this.rtcEngine.setCameraExposurePoint(normalizedCoords[0], normalizedCoords[1]);
this.exposurePointX = normalizedCoords[0].toFixed(2);
this.exposurePointY = normalizedCoords[1].toFixed(2);
console.info('Set exposure point:', this.exposurePointX, this.exposurePointY);
}
}フォーカスポイントの手動設定
ARTC は、手動でカメラのフォーカスポイントを設定する機能を提供します。この機能は露出ポイントのインターフェイスと似ていますが、カメラのフォーカス位置の調整に重点を置いています。この機能を使用する前に、isCameraFocusPointSupported を呼び出して、サポートされているかどうかを確認してください。
フォーカスポイントを手動で設定した後、フォーカスは静的になります。つまり、対象物の動きに連動してエリアを追跡したり、動的に調整されたりすることはありません。動的な追跡が必要な場合は、顔検出付きのオートフォーカス機能をご利用ください。
API リファレンス
/**
* @brief カメラが手動フォーカスをサポートしているかどうかを確認します。
* @return
* - true:対応。
* - false:非対応。
* @note この API は iOS および Android のみで利用可能であり、現在のカメラでフォーカスポイントの設定が可能なことを確認するために使用されます。
*/
public abstract boolean isCameraFocusPointSupported();
/**
* @brief カメラの手動フォーカスポイントを設定します。
* @param x X 座標値(正規化)。
* @param y Y 座標値(正規化)。
* @return
* - 0:成功。
* - 0 以外の値:失敗。
* @note この API は iOS および Android のみで利用可能です。このメソッドを呼び出した後、カメラは指定されたポイントで一度だけフォーカス調整を行い、その後そのフォーカス値を維持します。
*/
public abstract int setCameraFocusPoint(float x, float y);サンプル
以下のサンプルでは、シングルタップで露出ポイントを設定し、ダブルタップでフォーカスポイントを設定する方法を示します。
Android
mLocalViewGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
// ダブルタップを処理します。
if(mAliRtcEngine != null && mAliRtcEngine.isCameraFocusPointSupported()) {
float[] normalizedCoords = getNormalizedCoordinates(e.getX(), e.getY());
if (normalizedCoords[0] != -1 && normalizedCoords[1] != -1) {
mAliRtcEngine.setCameraFocusPoint(normalizedCoords[0], normalizedCoords[1]);
mCameraFocusPointX.setText(String.format("%.2f", normalizedCoords[0]));
mCameraFocusPointY.setText(String.format("%.2f", normalizedCoords[1]));
}
}
return true;
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
// シングルタップを処理します。
// ...
return true;
}
});iOS
@objc func handleSeatViewDoubleTap(_ gesture: UITapGestureRecognizer) {
guard let localSeatView = self.localPreviewSeatView else {
return
}
guard let rtcEngine = self.rtcEngine, rtcEngine.isCameraFocusPointSupported() else { return }
let tapPoint = gesture.location(in: localSeatView)
// タップ座標をビデオフレームの正規化座標(0 ~ 1 の範囲)に変換します。
let normalizedX = tapPoint.x / localSeatView.bounds.width
let normalizedY = tapPoint.y / localSeatView.bounds.height
rtcEngine.setCameraFocus(CGPoint(x: normalizedX, y: normalizedY))
self.cameraFocusPointXTextField.text = String(format: "%.2f", normalizedX)
self.cameraFocusPointYTextField.text = String(format: "%.2f", normalizedY)
}Harmony
private handleDoubleTap(touchX: number, touchY: number): void {
if (!this.rtcEngine) {
return;
}
// 正規化された座標を取得します。
const normalizedCoords = this.getNormalizedCoordinates(touchX, touchY);
if (normalizedCoords[0] !== -1 && normalizedCoords[1] !== -1) {
this.rtcEngine.setCameraFocusPoint(normalizedCoords[0], normalizedCoords[1]);
this.focusPointX = normalizedCoords[0].toFixed(2);
this.focusPointY = normalizedCoords[1].toFixed(2);
console.info('Set focus point:', this.focusPointX, this.focusPointY);
}
}顔検出付きオートフォーカス
ARTC SDK では、顔検出付きオートフォーカス機能を構成する API を提供しています。対応デバイスでは、この機能を有効化すると、ビデオフレーム内で顔を自動検出し、検出された顔が鮮明に保たれるようフォーカスを調整します。
ユースケース:この機能は、顔認識、ポートレート最適化、およびビデオ通話時の視覚品質向上に有効です。
開始する前に、isCameraAutoFocusFaceModeSupported を呼び出して、現在のデバイスがこの機能をサポートしているかどうかを確認してください。
API リファレンス
/**
* @brief カメラが顔検出付きオートフォーカス機能をサポートしているかどうかを確認します。
* @return
* - true:対応。
* - false:非対応。
* @note この API は iOS および Android のみで利用可能です。カメラがオフの場合には false を返します。
* カメラがオンで、かつ顔検出およびオートフォーカスの両方をサポートしている場合、true を返します。
*/
public abstract boolean isCameraAutoFocusFaceModeSupported();
/**
* @brief 顔検出付きオートフォーカス機能を有効化または無効化します。
* @param enable
* - true:有効化。
* - false:無効化。
* @return
* - true:成功。
* - false:失敗。
* @note この API は iOS および Android のみで利用可能です。{@link AliRtcEngine#isCameraAutoFocusFaceModeSupported} が true を返し、enable に true を指定した場合、カメラは検出された顔を継続的にフォーカスします。
*/
public abstract boolean setCameraAutoFocusFaceModeEnabled(boolean enable);サンプル
Android
if (mAliRtcEngine.isCameraAutoFocusFaceModeSupported()) {
mAliRtcEngine.setCameraAutoFocusFaceModeEnabled(isChecked);
}iOS
@IBAction func onCameraAudoFocusSwitch(_ sender: UISwitch) {
if ((self.rtcEngine?.isCameraAutoFocusFaceModeSupported()) != nil) {
self.rtcEngine?.setCameraAutoFocusFaceModeEnabled(sender.isOn)
}
}フラッシュの切り替え
ARTC SDK を使用すると、カメラのフラッシュをオン/オフに切り替えることができます。これは、低照度環境下やビデオ録画時、その他の特殊な照明条件下での明るさ調整に役立ちます。
この機能は iOS および Android のみで利用可能であり、ハードウェアフラッシュを搭載したデバイスが必要です。
フラッシュは通常、背面カメラのみで利用可能です。前面カメラには物理的なフラッシュが搭載されていないことが一般的です。一部のデバイスでは画面を用いた擬似的なフラッシュ効果を実装していますが、本 API ではその制御は行いません。
API リファレンス
/**
* @brief カメラのフラッシュをオン/オフに切り替えます。
* @param flash フラッシュをオンにするかどうかを指定します。
* @return
* - 0:成功。
* - 0 以外の値:失敗。
* @note この API は iOS および Android のみで利用可能です。通常、背面カメラのみがフラッシュを搭載しています。
*/
public abstract int setCameraFlash(boolean flash);サンプル
Android
mCameraFlashSwitch = findViewById(R.id.camera_flash_switch);
mCameraFlashSwitch.setEnabled(false);
mCameraFlashSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (mAliRtcEngine != null) {
mAliRtcEngine.setCameraFlash(isChecked);
}
});iOS
@IBOutlet weak var cameraFlashSwitch: UISwitch!
@IBAction func onCameraFlashSwitch(_ sender: UISwitch) {
if self.rtcEngine?.getCurrentCameraDirection() == .back {
self.rtcEngine?.setCameraFlash(sender.isOn)
}
}Harmony
private handleFlashChange(value: boolean): void {
if (!this.rtcEngine) {
return;
}
this.rtcEngine.setCameraFlash(value);
}