HarmonyOS鸿蒙Next中OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0

HarmonyOS鸿蒙Next中OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0

import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';

import { hilog } from '@kit.PerformanceAnalysisKit';
import streamingConnection from 'libstreaming.so';
import playerConnection from 'libplayer.so';

// import { camera } from '@kit.CameraKit'
// import { camera } from '@kit.CameraKit';
// import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { buffer } from '@kit.ArkTS';

// import { CameraDataModel } from '../model/CameraDateModel';

 

const DOMAIN = 0x0000;
const TAG = 'SecondPage'
@Entry
@Component
struct Index {
  private streamComponentCtl: XComponentController = new XComponentController();
  private playComponentCtl: XComponentController = new XComponentController();
  private streamComponentSurfaceId: string = '';
  private playComponentSurfaceId: string = '';
  @State imageWidth: number = 1920;
  @State imageHeight: number = 1080;
  private cameraManager: camera.CameraManager | undefined = undefined;
  private cameras: Array<camera.CameraDevice> | Array<camera.CameraDevice> = [];
  private cameraInput: camera.CameraInput | undefined = undefined;
  private previewOutput: camera.PreviewOutput | undefined = undefined;
  private session: camera.VideoSession | undefined = undefined;
  private uiContext: UIContext = this.getUIContext();
  private context: Context | undefined = this.uiContext.getHostContext();
  private cameraPermission: Permissions = 'ohos.permission.CAMERA'; // 申请权限相关问题可参考本篇开头的申请相关权限文档
  @State isShow: boolean = false;
  @State showText: string = ''
  private encoderVideoOutput:camera.VideoOutput | undefined = undefined;

  private peerConnection: number = 0;

  // 读取文件,解析为对象
  getRawFileJsonData() {
    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    let value: Uint8Array = context.resourceManager.getRawFileContentSync('join.json');
    let citystr = buffer.from(value.buffer).toString();
    let cityObj: ESObject = JSON.parse(citystr)

    console.info('join getRawFileJsonData:', JSON.stringify(cityObj)  )

    let videoProduceArrayvalue: Uint8Array = context.resourceManager.getRawFileContentSync('videoProduce.json');
    let videoProducestr = buffer.from(videoProduceArrayvalue.buffer).toString();
    let videoProduceObj: ESObject = JSON.parse(videoProducestr)
    console.info('videoProduceObj:', JSON.stringify(videoProduceObj)  )

    this.peerConnection = streamingConnection.DefineObject();
    streamingConnection.getValueStringJson(this.peerConnection, JSON.stringify(cityObj), JSON.stringify(videoProduceObj));

    let filesDir = context.filesDir;
    // console.info('getRawFileJsonData:', filesDir   );
    console.info(`initCamera getRawFileJsonData   filesDir: ${filesDir}  `);
  }

  async requestPermissionsFn(): Promise<void> {
    hilog.info(0x008666,  '', "requestPermissionsFn is printf ");
    let atManager = abilityAccessCtrl.createAtManager();
    if (this.context) {
      let res = await atManager.requestPermissionsFromUser(this.context, [this.cameraPermission]);
      for (let i = 0; i < res.permissions.length; i++) {
        if (this.cameraPermission.toString() === res.permissions[i] && res.authResults[i] === 0) {
          this.isShow = true;
        }
      }
      hilog.info(0x008666,  '', "requestPermissionsFn is 111 ");
    }
    hilog.info(0x008666,  '', "requestPermissionsFn is 666 ");
  }

  async requestPermissions() {
    let atManager = abilityAccessCtrl.createAtManager();
    let res = await atManager
      .requestPermissionsFromUser(this.context, [
        'ohos.permission.WRITE_IMAGEVIDEO',
        'ohos.permission.MEDIA_LOCATION',
        'ohos.permission.READ_MEDIA',
        'ohos.permission.WRITE_MEDIA',
        'ohos.permission.MICROPHONE',
        'ohos.permission.GET_NETWORK_INFO',
        'ohos.permission.MEDIA_LOCATION',
        'ohos.permission.INTERNET',
        'ohos.permission.READ_IMAGEVIDEO',
        'ohos.permission.KEEP_BACKGROUND_RUNNING',
        'ohos.permission.SYSTEM_FLOAT_WINDOW',
        'ohos.permission.FILE_ACCESS_PERSIST',
        'ohos.permission.READ_WRITE_DESKTOP_DIRECTORY',
       'ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY',
       'ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY'
      ])
      .then((data) => {
        this.showText = JSON.stringify(data.permissions)
        console.log('data permissions:' + data.permissions)
        console.log('data result:' + data.authResults)
      })
  }


  aboutToAppear(): void {
    this.requestPermissionsFn();
    this.requestPermissions();
    this.getRawFileJsonData();
  }

  onPageShow(): void {
    console.info('onPageShow');
    if (this.streamComponentSurfaceId !== '') {
      this.initCamera();
    }
  }

  onPageHide(): void {
    console.info('onPageHide');
    this.releaseCamera();
  }

  build() {
    Column() {
      if (this.isShow) {
        XComponent({
          id: 'componentId',
          type: XComponentType.SURFACE,
          controller: this.streamComponentCtl
        })
          .onLoad(async () => {
            console.info('onLoad is called');
            this.streamComponentCtl.setXComponentSurfaceSize({surfaceWidth: 1920,surfaceHeight: 1080});
            this.streamComponentCtl.setXComponentSurfaceRect({surfaceWidth: 1920,surfaceHeight: 1080});

            this.streamComponentSurfaceId = this.streamComponentCtl.getXComponentSurfaceId(); // 获取组件surfaceId。
            // 初始化相机,组件实时渲染每帧预览流数据。
            this.initCamera();
          })
          .width(/*this.uiContext.px2vp(this.imageHeight)*/ '100%')
          .height(/*this.uiContext.px2vp(this.imageWidth)*/ '40%')
          .id('streamComponentCtl')
          // .enableAnalyzer(true)
          // .position({ x: 400, y: 10 })
          // .backgroundColor('#00000000')

        XComponent({
          id: 'componentId',
          type: XComponentType.SURFACE,
          controller: this.playComponentCtl
        })
          .width('100%')
          .height('40%')
          .onLoad(async () => {

            this.playComponentCtl.setXComponentSurfaceSize({surfaceWidth: 1280,surfaceHeight: 720});
            this.playComponentCtl.setXComponentSurfaceRect({surfaceWidth: 1280,surfaceHeight: 720});

            this.playComponentSurfaceId = this.playComponentCtl.getXComponentSurfaceId();
            console.info('playComponentSurfaceId : ' + this.playComponentSurfaceId);
            streamingConnection.createDecoder(this.peerConnection,  BigInt (this.playComponentSurfaceId) );
          })
          .id('playComponentCtl_')
          // .enableAnalyzer(true)
          // .position({ x: 400, y: 10 })
          // .backgroundColor('#00000000')
          // .align(Alignment.End)
          //.margin({ top: '100%', left: '100%' })

        Button('切换屏幕').onClick(() => {
          // this.xAh = '100%'
          // this.xBw = '50%'
          // this.xbM = '20%'
          // this.xbM_L = '50%'
          // window.getLastWindow(this.getUIContext()?.getHostContext(), (err, win) => {
          //   win.setPreferredOrientation(window.Orientation.LANDSCAPE_INVERTED)
          // })
        })

      }
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }

  getCameraDevices(cameraManager: camera.CameraManager): Array<camera.CameraDevice> {
    let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras();
    if (cameraArray != undefined && cameraArray.length > 0) {
      for (let index = 0; index < cameraArray.length; index++) {
        console.info('cameraId : ' + cameraArray[index].cameraId);  // 获取相机ID。
        console.info('cameraPosition : ' + cameraArray[index].cameraPosition);  // 获取相机位置。
        console.info('cameraType : ' + cameraArray[index].cameraType);  // 获取相机类型。
        console.info('connectionType : ' + cameraArray[index].connectionType);  // 获取相机连接类型。
        hilog.info(0x008666, TAG, "getCameraDevices is printf ");
      }
      return cameraArray;
    } else {
      console.error("cameraManager.getSupportedCameras error");
      return [];
    }
  }
  // 初始化相机。
  async initCamera(): Promise<void> {
    console.info(`initCamera previewOutput streamComponentSurfaceId:${this.streamComponentSurfaceId}  filesDir: ${getContext().filesDir}  `);
    hilog.info(DOMAIN, 'testTag', 'initCamera NAPI 2 + 3 = %{public}d', 5);
    let encoderSurfaceId: string = streamingConnection.startConnection(this.peerConnection);
    try {
      // 获取相机管理器实例。
      this.cameraManager = camera.getCameraManager(this.context);
      if (!this.cameraManager) {
        console.error('initCamera getCameraManager');
        return;
      }
      // 获取当前设备支持的相机device列表。
      this.cameras = this.cameraManager.getSupportedCameras();
      if (!this.cameras) {
        console.error('initCamera getSupportedCameras');
      }

      if (this.cameras != undefined && this.cameras.length > 0) {
        for (let index = 0; index < this.cameras.length; index++) {
          console.info('cameraId : ' + this.cameras[index].cameraId);  // 获取相机ID。
          console.info('cameraPosition : ' + this.cameras[index].cameraPosition);  // 获取相机位置。
          console.info('cameraType : ' + this.cameras[index].cameraType);  // 获取相机类型。
          console.info('connectionType : ' + this.cameras[index].connectionType);  // 获取相机连接类型。
          hilog.info(0x008666, TAG, "getCameraDevices is printf ");
        }
      }

      // 选择一个相机device,创建cameraInput输出对象。
      this.cameraInput = this.cameraManager.createCameraInput(this.cameras[1]);
      if (!this.cameraInput) {
        console.error('initCamera createCameraInput');
        return;
      }
      // 打开相机。
      await this.cameraInput.open();
      // 获取相机device支持的profile。
      let capability: camera.CameraOutputCapability =
        this.cameraManager.getSupportedOutputCapability(this.cameras[0], camera.SceneMode.NORMAL_VIDEO);
      if (!capability || capability.previewProfiles.length === 0) {
        console.error('capability is null || []');
        this.releaseCamera();
        return;
      }
      let minRatioDiff : number = 0.1;
      let surfaceRatio : number = this.imageWidth / this.imageHeight; // 最接近16:9宽高比。
      let previewProfile: camera.Profile = capability.previewProfiles[0];
      console.info(`initCamera width:${previewProfile.size.width} height:${previewProfile.size.height}`);
      // 应用开发者根据实际业务需求选择一个支持的预览流previewProfile。
      // 此处以选择CAMERA_FORMAT_YUV_420_SP(NV21)格式、满足限定条件分辨率的预览流previewProfile为例。
      for (let index = 0; index < capability.previewProfiles.length; index++) {
        const tempProfile = capability.previewProfiles[index];
        console.info(`get camera format:${tempProfile.format} index:${index}`);
        let tempRatio = tempProfile.size.width >= tempProfile.size.height ?
          tempProfile.size.width / tempProfile.size.height : tempProfile.size.height / tempProfile.size.width;
        let currentRatio = Math.abs(tempRatio - surfaceRatio);
        if (currentRatio <= minRatioDiff && tempProfile.format == camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP) {
          previewProfile = tempProfile;
          break;
        }
      }

      previewProfile.size.width = previewProfile.size.width*3;
      previewProfile.size.height = previewProfile.size.height*3;

      this.imageWidth = previewProfile.size.width; // 更新xComponent组件的宽。
      this.imageHeight = previewProfile.size.height; // 更新xComponent组件的高。
      console.info(`initCamera imageWidth:${this.imageWidth} imageHeight:${this.imageHeight}`); // initCamera imageWidth:1920 imageHeight:1080

      // 使用xComponentSurfaceId创建预览。
      this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.streamComponentSurfaceId);
      if (!this.previewOutput) {
        console.error('initCamera createPreviewOutput');
        this.releaseCamera();
        return;
      }
      // 创建录像模式相机会话。
      let session = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO);
      if (!session) {
        console.error('session is null');
        this.releaseCamera();
        return;
      }
      console.info(`initCamera size0:${capability.videoProfiles[0].size.height} size1:${capability.videoProfiles[1].size.height},width0:${capability.videoProfiles[0].size.width} width1:${capability.videoProfiles[1].size.width} `);
      let encodeProfile: camera.VideoProfile  = capability.videoProfiles[0];
      encodeProfile.size.width = this.imageWidth;
      encodeProfile.size.height = this.imageHeight;
      //Create the encoder output object
      this.encoderVideoOutput  = this.cameraManager.createVideoOutput(encodeProfile, encoderSurfaceId);
      if (this.encoderVideoOutput === undefined) {
        console.error(TAG, 'encoderVideoOutput is undefined');
        return;
      }
      console.info(TAG, 'encoderVideoOutput  success');

      this.session = session as camera.VideoSession;
      // 开始配置会话。
      this.session.beginConfig();
      // 添加相机设备输入。
      this.session.addInput(this.cameraInput);
      // 添加预览流输出。
      this.session.addOutput(this.previewOutput);

      this.session.addOutput(this.encoderVideoOutput);
      // 提交会话配置。
      await this.session.commitConfig();
      // 开始启动已配置的输入输出流。
      await this.session.start();

      this.encoderVideoOutput.start((err: BusinessError) => {
        if (err) {
          console.error(TAG, `Failed to start the encoder video output. error: ${JSON.stringify(err)}`)
          return
        }
        console.info(TAG, 'Callback invoked to indicate the encoder video output start success.')
      });
      console.info(`initCamera start `);
      streamingConnection.encoderStart();
    } catch (error) {
      console.error(`initCamera fail: ${JSON.stringify(error)}`);
      this.releaseCamera();
    }
  }

  // 释放相机。
  async releaseCamera(): Promise<void> {
    console.info('releaseCamera');
    // 停止当前会话。
    await this.session?.stop().catch((e: BusinessError) => {console.error('Failed to stop session: ', e)});
    // 释放相机输入流。
    await this.cameraInput?.close().catch((e: BusinessError) => {console.error('Failed to close the camera: ', e)});
    // 释放预览输出流。
    await this.previewOutput?.release().catch((e: BusinessError) => {console.error('Failed to stop the preview stream: ', e)});
    // 释放会话。
    await this.session?.release().catch((e: BusinessError) => {console.error('Failed to release session: ', e)});
  }
}
void OhoHardWareDecoder::start(uint64_t surfaceId)
{
    OH_AVErrCode ret;
    this->nativeWindow = nullptr;
    // 基于步骤1.1中获取的surfaceId创建对应的nativeWindow实例。
    int success = OH_NativeWindow_CreateNativeWindowFromSurfaceId(surfaceId, &nativeWindow);
    if (!success || nativeWindow == nullptr) {
       OH_LOG_ERROR(LOG_APP, "OH_NativeWindow_CreateNativeWindowFromSurfaceId Failed to create native window ,ret %{public}d ",success);
//       return; // 处理错误
    }
//    OH_LOG_ERROR(LOG_APP, "OH_NativeWindow_CreateNativeWindowFromSurfaceId ret %{public}d ", ret1); // 异常处理。
   // 设置surface。 配置送显窗口参数。
   if(nativeWindow == nullptr)
   {
      OH_LOG_ERROR(LOG_APP, "nativeWindow error"); // 异常处理。
   }
   ret = OH_VideoDecoder_SetSurface(videoDec, nativeWindow);  // nativeWindow通过以上两种方式获取。
   if (ret != AV_ERR_OK) {
      OH_LOG_ERROR(LOG_APP,"OH_VideoDecoder_SetSurface error "); // 异常处理。
   }
   // 配置视频与显示屏匹配模式(缓冲区按原比例缩放,使得缓冲区的较小边与窗口匹配,较长边超出窗口的部分被视为透明)。
//   OH_NativeWindow_NativeWindowSetScalingModeV2(nativeWindow, OH_SCALING_MODE_SCALE_CROP_V2);
    
   ret = OH_VideoDecoder_Prepare(videoDec);
   if (ret != AV_ERR_OK) {
      OH_LOG_ERROR(LOG_APP,"OH_VideoDecoder_Prepare error "); // 异常处理。
   }
    // 启动解码

更多关于HarmonyOS鸿蒙Next中OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0表示函数执行失败。该函数用于通过Surface ID创建NativeWindow对象,返回0通常意味着传入的Surface ID无效或系统资源不足。可能原因包括:Surface ID不存在、已被销毁,或内存分配失败。需检查Surface ID来源及生命周期管理,确保在有效状态下调用。该接口属于Native Window模块,用于图形渲染操作。

更多关于HarmonyOS鸿蒙Next中OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,OH_NativeWindow_CreateNativeWindowFromSurfaceId返回0表示创建NativeWindow失败。从代码分析,问题可能出现在以下几个方面:

  1. SurfaceId传递问题:在ArkTS代码中,playComponentSurfaceId通过getXComponentSurfaceId()获取后,在C++层被转换为BigInt类型传递。需要确认:

    • SurfaceId是否在XComponent完全加载后获取
    • 传递过程中数据类型转换是否正确
    • SurfaceId是否有效且不为空
  2. 时序问题:确保在调用OH_NativeWindow_CreateNativeWindowFromSurfaceId时:

    • XComponent已成功创建并初始化
    • Surface已就绪可用
    • 没有在组件未加载完成时提前获取SurfaceId
  3. 权限和配置

    • 确认所有必要的媒体权限已正确申请
    • 检查XComponent的尺寸设置是否合理
    • 验证视频解码器的配置参数

建议在调用OH_NativeWindow_CreateNativeWindowFromSurfaceId前添加日志,确认SurfaceId的值和状态,并检查NativeWindow创建失败的具体错误码。

回到顶部