【官方总结】HarmonyOS鸿蒙Next应用开发FAQ汇总-媒体

【官方总结】HarmonyOS鸿蒙Next应用开发FAQ汇总-媒体

1.HarmonyOS如何使用ets访问系统图库(eTS)(API 8)

// 导入模块
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import featureAbility from '@ohos.ability.featureAbility';
// 创建媒体数据管理器的实例
var mediaLibraryInstance = mediaLibrary.getMediaLibrary(); 
// 启动媒体选择界面
let option = {
 type : "image",
 count : 5
};
mediaLibraryInstance.startMediaSelect(option).then(value => {
 console.log("Media resources selected.");
 this.imageArr = value;
}).catch(err => {
 console.log("An error occurred when selecting media resources.");
});

2.HarmonyOS使用JS框架读取本地音乐还需要用到音乐在设备上的绝对路径?有点麻烦,有案例吗(eTS)(API 8)

请参考: https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-medialibrary.md

3.HarmonyOS如何使用JS实现音频录制(JS)(API 8)

媒体管理API提供了音频播放、音频录制等相关能力。请参考: https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-media-0000001103383404

4.HarmonyOS中JS媒体组件camera拍照成功后,如何将图片保存到手机相册(JS)(API8)

拍照成功后,回调函数会返回图片的uri,使用媒体数据管理提供的storeMediaAsset()可以将图片保存到本地相册,请参考: https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-medialibrary-0000001168747257#section964512672913

5. SurfaceProvider如何加载resource下的图片资源(Java)(API 6)

SurfaceProvider暂时不能直接加载resource下的图片资源。以下提供两种加载resource下图片的方法:

方法一

Image image = (Image) findComponentById(ResourceTable.Id_image);
PixelMapElement element = new PixelMapElement(image.getPixelMap());
SurfaceProvider surfaceProvider = new SurfaceProvider(this);
surfaceProvider.setBackground(element);
PixelMapElement backgroundElement = (PixelMapElement) surfaceProvider.getBackgroundElement();
PixelMap pixelMap = backgroundElement.getPixelMap();

方法二

private static final int DESIRE_WIDTH = 100;
private static final int DESIRE_HEIGHT = 100;
...
InputStream source = null;
ImageSource imageSource = null;
try {
  source = this.getResourceManager().getResource(ResourceTable.Media_a);
  imageSource = ImageSource.create(source, null);
  ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
  decodingOpts.desiredSize = new Size(DESIRE_WIDTH , DESIRE_HEIGHT);
  PixelMap pixelmap = imageSource.createPixelmap(decodingOpts);
} catch (IOException | NotExistException e) {
 ……
} finally {
   try {
    source.close();
  } catch (IOException e) {
    ……
  }
}

6. HarmonyOS如何把resource图片转成URI(Java)(API 6)

String path = null;
try {
  path = getResourceManager().getMediaPath(ResourceTable.xxx);
} catch (IOException e) {
  HiLog.error(LABEL_LOG,e.getMessage());
} catch (NotExistException e) {
  HiLog.error(LABEL_LOG,e.getMessage());
} catch (WrongTypeException e) {
  HiLog.error(LABEL_LOG,e.getMessage());
}
Uri uri = Uri.parse(path);

7. HarmonyOS中如何实现触摸缩放图片(Java)(API 6)

// 开始的参考点以两个触摸点的中心为准
Matrix matrix = new Matrix();
float scale = endDis / startDis;
matrix.setMatrix(currentMatrix);
// 参数1,2指定在x,y轴的放大倍数;参数3,4为缩放参考点的x,y轴坐标
matrix.postScale(scale, scale, midPoint.getX(), midPoint.getY());
// 图片缩放
image.addDrawTask((component,canvas)->
{
 // 通过矩阵实现缩放
 canvas.setMatrix(matrix);
});

8. 参看AudioDeviceDescriptor的API编写代码播放一段mp3音频总是没有声音(Java)(API 6)

AudioDeviceDescriptor不是支持音视频播放的接口类。目前HarmonyOS提供的可播放mp3格式的sdk接口是harmonyos.media.player.Player。

示例代码如下:

try (FileInputStream in = new FileInputStream(new File(PLAYER_TEST_FILE))) {
   FileDescriptor fd = in.getFD();
   Source source = new Source(fd);
   Player impl = new Player(this);
   impl.setSource(source);
   impl.prepare();
   impl.play();
 } catch (IOException e) {
   ...
 }

具体使用方法请参考: Player API参考

9. 如何持续获取相机的帧数据(Java)(API 6)

1.在相机配置时调用 setFrameStateCallback(FrameStateCallback callback, EventHandler handler)方法设置帧回调。 2.通过camera.triggerLoopingCapture(FrameConfig)方法实现循环帧捕获。

具体使用方法请参考: 相机设备开发指导

10. 如何使用AudioRenderer的参数(Java)(API 6)

参照如下代码,配置AudioStreamInfo :

配置AudioStreamInfo

// 44.1kHz
final int RATE = 44100;
AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
  // 采样率
  .sampleRate(RATE)
  // 混音
  .audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_MAY_DUCK)
  // 16-bit PCM
  .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
  // 双声道输出
  .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_OUT_STEREO)
  // 媒体类音频
  .streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_MEDIA)
  .build();

配置AudioRendererInfo

final int BUFFER_SIZE = 1024;
AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder()
  .audioStreamInfo(audioStreamInfo)
  // pcm格式的输出流
  .audioStreamOutputFlag(
      AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_DIRECT_PCM)
  .bufferSizeInBytes(BUFFER_SIZE)
  // false表示分段传输buffer并播放,true表示整个音频流一次性传输到HAL层播放
  .isOffload(false)
  .build();

初始化AudioRenderer

AudioRenderer audioRenderer = new AudioRenderer(audioRendererInfo,AudioRenderer.PlayMode.MODE_STREAM);

文件读取

final int BUFFER_SIZE = 1024;
final int FLAG_INT = -1;
File file = new File("test.wav");
FileInputStream soundInputStream;
int bufSize = audioRenderer.getBufferFrameSize();
byte[] buffer = new byte[BUFFER_SIZE];
int len;
try {
  soundInputStream = new FileInputStream(file);
  audioRenderer.start();
  while ((len = soundInputStream.read(buffer, 0, buffer.length)) != FLAG_INT) {
    audioRenderer.write(buffer, 0, buffer.length);
  }
  soundInputStream.close();
} catch (IOException e) {
  HiLog.error(LABEL_LOG, e.getMessage());
}

11. 音频播放,使用文件输出流写数据后,发现文件写后结果总是Null(Java)(API 6)

原因为getGlobalTaskDispatcher的asyncDispatch方法异步导致,采用getGlobalTaskDispatcher的syncDispatch方法同步操作。

12. CameraId的获取是否可以理解为本机可以获取分布式设备支持的camera,还是只是可以获取自身设备的camera(Java)(API 6)

CameraId指的是逻辑相机的Id,与分布式没有关系,不能获取远端CameraId。

物理相机是独立的实体摄像头设备。物理相机Id是用于标志每个物理摄像头的唯一字串。

逻辑相机是多个物理相机组合出来的抽象设备,逻辑相机通过同时控制多个物理相机设备来完成相机某些功能,如大光圈、变焦等功能。多个物理摄像头合在一起组成了一个唯一的字串,此字串即逻辑相机Id。

13. PixelMap如何保存成本地图片文件(Java)(API 6)

如下代码提供将PixelMap对象转换成new.jpeg图片并保存的例子,请参考:

private static final HiLogLabel LABEL_LOG = new HiLogLabel(0, 0, "LogUtil");
private static final String LOG_FORMAT = "%{public}s: %{public}s";

ImagePacker imagePacker = ImagePacker.create();
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "new.jpeg");
FileOutputStream outputStream = null;
try {
   outputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
  HiLog.info(LABEL_LOG, LOG_FORMAT, "", "out put file path is incorrect");
}

ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();
packingOptions.format = "image/jpeg";
packingOptions.quality = 100;// 设置图片质量
boolean result = imagePacker.initializePacking(outputStream, packingOptions);
result = imagePacker.addImage(pixelMap);
long dataSize = imagePacker.finalizePacking();

开发者文档请参考如下链接: https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-image-encoding-0000001050994971

14. 如何获取视频的第一帧作为视频的封面(Java)(API 6)

1.创建媒体数据管理AVMetadataHelper对象,可以通过setSource设置要读取的媒体文件,如果不设置或设置不正确,则无法进行后续操作。

AVMetadataHelper avMetadataHelper = new AVMetadataHelper ();
avMetadataHelper.setSource("/data/data/com.huawei.multimedia/video.mov");

2.指定获取帧数据的选项,以及获取帧的时间,获取媒体源的帧数据。

PixelMap pixelMap = avMetadataHelper.fetchVideoPixelMapByTime(1000L, 0x00);

3.获取到PixelMap对象后,调用release()函数释放读取的媒体资源。

avMetadataHelper.release();

15. 调用相机预览时黑屏如何解决(Java)(API 6)

在设置surfaceProvider组件属性时增加如下代码:

getWindow().setTransparent(true);
surfaceProvider.pinToZTop(false);

16. JS API中如何播放音频,使用无效(Java)(API 6)

使用video可以实现音频播放,注意资源文件引入路径是否正确:

<video src=""></video>

17. HarmonyOS相机如何进入单帧捕获生成图像回调(Java)(API 6)

1.创建ImageReceiver对象并绑定监听。

private static final int CAPACITY = 5;
private void takePictureInit() {
  List<Size> pictureSizes = cameraAbility.getSupportedSizes(ImageFormat.JPEG); // 获取拍照支持分辨率列表
  pictureSize = getpictureSize(pictureSizes); // 根据拍照要求选择合适的分辨率
  imageReceiver = ImageReceiver.create(Math.max(pictureSize.width, pictureSize.height),
      Math.min(pictureSize.width, pictureSize.height),
      ImageFormat.JPEG, CAPACITY); // 创建ImageReceiver对象,注意create函数中宽度要大于高度;5为最大支持的图像数,请根据实际设置。
  imageReceiver.setImageArrivalListener(imageArrivalListener);
}

2.触发对应事件。

cameraDevice.triggerSingleCapture(pictureFrameConfig);

相机开发请参考: https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/HarmonyOS-DistributedCamera

18. 如何用canvas画出旋转的图片(Java)(API 6)

通过canvas的rotate方法实现图片旋转动画:

1.将图片转换成PixelMap

public PixelMap getPixelMap() {
InputStream drawableInputStream = null;
PixelMap pixelMap = null;
try {
  drawableInputStream = this.getResourceManager().getResource(ResourceTable.Media_delete);
  ImageSource imageSource = ImageSource.create(drawableInputStream, new ImageSource.SourceOptions());
  ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
  pixelMap = imageSource.createPixelmap(options);
  return pixelMap;
} catch (IOException | NotExistException exception) {
  HiLog.error(LABEL_LOG, "IOException | NotExistException", exception.getMessage());
} finally {
  if (drawableInputStream != null) {
    try {
      drawableInputStream.close();
    } catch (IOException e) {
      HiLog.error(LABEL_LOG, "IOException", e.getMessage());
    }
  }
}
return pixelMap;
}

2.在onDraw方法中画图片。

Component componentById = findComponentById(ResourceTable.Id_main_layout);
componentById.addDrawTask(new Component.DrawTask() {
  @Override
  public void onDraw(Component component, Canvas canvas)
  {
    PixelMap pixelMap = getPixelMap();
    PixelMapHolder pmh = new PixelMapHolder(pixelMap);

    // 以(x,y)为中心点,将画布旋转degree角度
    canvas.rotate(degree, x, y);
    canvas.drawPixelMapHolder(
        pmh,
        0,
        0,
        new Paint());

  }
});

3.如果想让图片持续旋转,实现旋转动画,可以持续改变degree的值,然后调用invalidate()方法。

19. HarmonyOS相机如何获取和设置曝光值(Java)(API 6)

相机可以获取和设置曝光模式,不能直接获取到值。

getSupportedAeMode(),获取当前相机支持的自动曝光模式。

setAeMode(int aeMode, Rect rect),配置曝光模式。

详细信息请参考: https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-camera-guidelines-0000000000031782

20. 如何一直开启闪光灯(Java)(API 6)

将闪光灯设置为FLASH_ALWAYS_OPEN模式,闪光灯会一直开启,示例代码如下:

private FrameConfig.Builder framePreviewConfigBuilder;
private Camera qrCamera;

// 打开闪光灯
public void openFlashlight() {
  framePreviewConfigBuilder.setFlashMode(Metadata.FlashMode.FLASH_ALWAYS_OPEN);
  qrCamera.triggerLoopingCapture(framePreviewConfigBuilder.build());
}

21. 如何使播放器支持播放网络视频(Java)(API 6)

1.访问外网,需要在config.json中添加INTERNET权限,如下所示:

"reqPermissions": [
 {
  "name": "ohos.permission.INTERNET"
 }
]

2.鸿蒙的默认是https访问模式,如果您的请求网址是http开头的,请在config.json文件中的deviceConfig下,添加如下设置:

"deviceConfig": {
 "default": {
  "network": {
   "cleartextTraffic": true
  }
 }
},

3.初始化SurfaceProvider及Player:

// 网络地址
private String url ="";
private SurfaceProvider surfaceProvider;
private Player player;

private void initSurfaceProviderPlayer() {
  surfaceProvider= (SurfaceProvider) findComponentById(ResourceTable.Id_surfaceProvider);
  surfaceProvider.pinToZTop(true);// 不设置这个 画面不显示;

  player=new Player(getContext());
  surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() {
    @Override
    public void surfaceCreated(SurfaceOps surfaceOps) {
      // 这里设置的播放源为网络地址,
      player.setSource(new Source(url));

      player.setVideoSurface(surfaceOps.getSurface());
      player.prepare();
    }
     
    @Override
    public void surfaceChanged(SurfaceOps holder, int format, int width, int height) {
    }
     
    @Override
    public void surfaceDestroyed(SurfaceOps surfaceOps) {
    }

  });
}

4.调用play()方法播放:

if (player != null) {
   player.play();
}

22. 如何将PixelMap转化为Byte数组(Java)(API 6)

参考如下代码:

private PixelMap readLogoPixelmap(Context context) {
  PixelMap logoPixelMap = null;
  try {
    ImageSource logoSource = ImageSource.create(
        context.getResourceManager().getResource(ResourceTable.Media_icon),
        null);
    ImageSource.DecodingOptions opts = new ImageSource.DecodingOptions();
    opts.editable = true;
    logoPixelMap = logoSource.createPixelmap(opts);
  } catch (IOException | NotExistException e) {
    HiLog.info(LABEL_LOG, "read error");
  }
  return logoPixelMap;
}
// 获取PixelMap图像,并写入ByteBuffer中。
PixelMap pixelMap = readLogoPixelmap(context);
Size size = pixelMap.getImageInfo().size;
ByteBuffer byteBuffer = ByteBuffer.allocate(size.width * size.height * 4);
pixelMap.readPixels(byteBuffer);
byteBuffer.flip();

23. Player开发视频播放,如何实现重播功能(Java)(API 6)

1.准备播放地址:

private String url ="";

2.在xml布局添加SurfaceProvider:

<SurfaceProvider
  ohos:height="match_parent"
  ohos:width="match_parent"
  ohos:id="$+id:surfaceProvider"
  />

3.初始化SurfaceProvider及Player:

private SurfaceProvider surfaceProvider;
private Player player;

private void initSurfaceProviderPlayer() {
  surfaceProvider= (SurfaceProvider) findComponentById(ResourceTable.Id_surfaceProvider);
  surfaceProvider.pinToZTop(true);// 不设置这个 画面不显示;

  player=new Player(getContext());
  surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() {
    @Override
    public void surfaceCreated(SurfaceOps surfaceOps) {
      // 这里设置的播放源为网络地址,
      player.setSource(new Source(url));

      player.setVideoSurface(surfaceOps.getSurface());
      player.prepare();
    }
     
    @Override
    public void surfaceChanged(SurfaceOps holder, int format, int width, int height) {
    }
     
    @Override
    public void surfaceDestroyed(SurfaceOps surfaceOps) {
    }

  });
  // 设置播放回调接口
  player.setPlayerCallback(new Player.IPlayerCallback() {
    //这里省略其他实现方法

    //这个方法在视频播放后回调,执行play()实现重播;
    @Override
    public void onPlayBackComplete() {
      if (player != null) {
        player.play();
      }
    }

  });
}

3.点击按钮实现播放(按钮控件自行在xml添加):

findComponentById(ResourceTable.Id_play).setClickedListener(new Component.ClickedListener() {
  @Override
  public void onClick(Component component) {
    if (player != null) {
      player.play();
    }
  }
});

24. HarmonyOS如何实现图片切换动画(Java)(API 6)

使用属性动画AnimatorProperty实现图片切换动画,参考以下代码:

Image image;
AnimatorProperty animator = image.createAnimatorProperty();
animator.moveFromX(50).moveToX(1000).rotate(180).alpha(0).setDuration(2500).setDelay(500).setLoopedCount(5);
animator.start();
//可以使用setTarget()改变关联的Component对象。
Image image2;
animator.setTarget(image2);

25. 如何获取图片的宽高(Java)(API 6)

请参考如下代码实现:

public class MainAbilitySlice extends AbilitySlice {
  private PixelMap pixelMap;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    Size size = pixelMap.getImageInfo().size;
    int width = size.width;
    int height = size.height;

  }
}

26.获取视频截图报错(Java)(API 6)

setSource(FileDescriptor fd) 这种公共目录资源不能直接访问,可以通过数据库进行访问,参考如下代码:

Context context = getContext();
Uri myUri = AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI;
DataAbilityHelper helper = DataAbilityHelper.creator(context);
try {
    DataAbilityPredicates dataAbilityPredicates = new DataAbilityPredicates("_id>?");
    dataAbilityPredicates.setWhereArgs(Arrays.asList("0"));
    ResultSet result = helper.query(myUri, null, null);
    if (result == null) {
      return;
    }
    while (result.goToNextRow()) {
      int anInt = result.getInt(result.getColumnIndexForName(AVStorage.Video.Media.ID));
      Uri uri = Uri.appendEncodedPathToUri(AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI,
            String.valueOf(anInt));
      FileDescriptor fd = helper.openFile(uri, "r");
      AVMetadataHelper avMetadataHelper = new AVMetadataHelper();
      avMetadataHelper.setSource(fd);
      avMetadataHelper.release();
     }
   } catch (DataAbilityRemoteException | FileNotFoundException e) {
      // ...
   }

27.HarmonyOS相机纵向、横向拉伸问题该如何处理(Java)(API 6)

自定义相机预览变形需要在surfaceProvider回调surfaceCreated时设置尺寸,以当前控件宽高为准,如以下代码所示:

surfaceCreated(SurfaceOps surfaceOps) {
  surfaceOps.setFixedSize(getHeight(), getWidth());
  ...
}

竖屏拍照可以设置照片角度,如以下代码所示:

// 调用拍照
public void capture() {
  // 获取拍照配置模板
  FrameConfig.Builder pictureFrameConfigBuilder =
  cameraDevice.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PICTURE);
  // 配置拍照surface
  pictureFrameConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
  // 设置照片角度
  pictureFrameConfigBuilder.setImageRotation(90);
  try {
  // 启动拍照
    cameraDevice.triggerSingleCapture(pictureFrameConfigBuilder.build());
  } catch (Exception e) {
    e.printStackTrace();
  }
}
6 回复

请问楼主player的onPlayerBackComplete回调经常不走,偶然会走是怎么回事呢

更多关于【官方总结】HarmonyOS鸿蒙Next应用开发FAQ汇总-媒体的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


学习收藏了,感谢分享!

学习收藏了,感谢分享!

非常感谢楼主的分享!

HarmonyOS鸿蒙Next应用开发中,媒体相关的FAQ主要涉及音频、视频、图像等多媒体功能的实现与优化。以下是一些常见问题及解答:

  1. 如何实现音频播放?

    • 使用AudioPlayer类进行音频播放,支持本地和网络音频资源。通过prepare()play()pause()stop()等方法控制播放状态。
  2. 如何实现视频播放?

    • 使用VideoPlayer类进行视频播放,支持本地和网络视频资源。通过prepare()start()pause()stop()等方法控制播放状态。
  3. 如何实现图像加载与显示?

    • 使用Image组件加载和显示图像,支持本地和网络图像资源。通过src属性指定图像源,widthheight属性设置图像尺寸。
  4. 如何实现音频录制?

    • 使用AudioRecorder类进行音频录制,支持设置采样率、声道数、编码格式等参数。通过start()pause()resume()stop()等方法控制录制过程。
  5. 如何实现视频录制?

    • 使用VideoRecorder类进行视频录制,支持设置分辨率、帧率、编码格式等参数。通过start()pause()resume()stop()等方法控制录制过程。
  6. 如何实现图像处理?

    • 使用Image类进行图像处理,支持裁剪、旋转、缩放、滤镜等操作。通过getPixelMap()获取图像像素数据,进行进一步处理。
  7. 如何实现多媒体资源管理?

    • 使用MediaLibrary类进行多媒体资源管理,支持查询、添加、删除、修改等操作。通过getMediaAssets()获取多媒体资源列表。
  8. 如何实现多媒体事件监听?

    • 使用MediaEventListener类进行多媒体事件监听,支持播放完成、播放错误、播放状态变化等事件。通过onEvent()方法处理事件。
  9. 如何实现多媒体资源缓存?

    • 使用MediaCache类进行多媒体资源缓存,支持设置缓存大小、缓存路径等参数。通过put()get()remove()等方法管理缓存。
  10. 如何实现多媒体资源加密?

    • 使用MediaEncryptor类进行多媒体资源加密,支持设置加密算法、密钥等参数。通过encrypt()decrypt()等方法进行加密解密操作。

以上是HarmonyOS鸿蒙Next应用开发中媒体相关的常见问题及解答。

HarmonyOS鸿蒙Next应用开发中,媒体相关FAQ主要涉及音频、视频、图像处理等功能的实现与优化。开发者常遇到音频播放延迟、视频编解码兼容性、图像渲染性能等问题。建议使用系统提供的MediaPlayer、VideoView等组件,并遵循官方文档进行参数配置与性能调优。同时,关注设备硬件差异,确保应用在不同设备上的兼容性与稳定性。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!