当前位置:   article > 正文

【HarmonyOS】实现从视频提取音频并保存到pcm文件功能(API6 Java)_鸿蒙视频解码 videodecoder

鸿蒙视频解码 videodecoder

 【关键字

视频提取类Extractor、视频编解码、保存pcm文件

【写在前面】

在使用API6开发HarmonyOS应用时,通常会开发一些音视频媒体功能,这里介绍如何从视频中提取音频保存到pcm文件功能,生成pcm音频文件后,就可使用音频播放类AudioRenderer进行播放了。这里主要介绍从视频提取音频并保存到pcm文件的开发步骤。

【开发步骤】

步骤1:对视频格式的文件进行提取音频文件,并通过解码器解码并监听获取到的buffer数据;直接使用Extractor从视频中提取出来的音频数据不能直接作为类似pcm数据源进行播放,需要使用解码器解码之后得到的原始数据才可AudioRenderer进行播放。新建VideoDecoder类,在里面封装相关功能代码。使用Extractor从视频提取音频数据并使用解码器解码,代码如下:

  1. // 可创建VideoDecoder类,实现相关功能
  2. private Format format;
  3. private Codec decoder;
  4. private Extractor extractor;
  5. public void createDecoder() {
  6. decoder = Codec.createDecoder(); // 创建解码器
  7. extractor = new Extractor(); // 创建Extractor解封装类
  8. boolean ret = extractor.setSource(new Source("/data/data/com.harmonyospro.myapplication/vedio_audio_test.mp4")); // 设置数据源,com.harmonyospro.myapplication为应用包名;也可设置为网络视频数据源
  9. System.out.println("setSource ret = " + ret);
  10. int trackCount = extractor.getTotalStreams();//获取轨道
  11. for (int i = 0; i < trackCount; i++) {
  12. format = extractor.getStreamFormat(i);
  13. if (format.getStringValue("mime").contains("audio")) { // 视频video,audio音频
  14. /**
  15. * @tc.steps: step2.set codec format for decoder
  16. * @tc.expected: step2.the return value is true
  17. */
  18. ret = decoder.setCodecFormat(format);
  19. System.out.println("setCodecFormat ret = " + ret);
  20. ret = extractor.specifyStream(i);
  21. System.out.println("specifyStream ret = " + ret);
  22. System.out.println("format.toString() = " + format.toString());
  23. System.out.println("format.getStringValue(mine) = "+format.getStringValue("mime"));
  24. System.out.println("format.getStringValue(width) = "+format.getIntValue("width"));
  25. System.out.println("format.getStringValue(height) = "+format.getIntValue("height"));
  26. break;
  27. }
  28. }
  29. decoder.registerCodecListener(listener);
  30. }
  31. Codec.ICodecListener listener = new Codec.ICodecListener() {
  32. @Override
  33. public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int i) {
  34. Format fmt = decoder.getBufferFormat(byteBuffer);
  35. System.out.println("fmt.toString() = " + fmt.toString());
  36. // 写入文件
  37. writeFile(byteBuffer,bufferInfo,i);
  38. System.out.println("onReadBuffer == " + bufferInfo.toString());
  39. }
  40. @Override
  41. public void onError(int errorCode, int act, int trackId) {
  42. throw new RuntimeException();
  43. }
  44. };
  45. /**
  46. * 调用 start()方法开始解码
  47. */
  48. public void start(){
  49. boolean start = decoder.start();
  50. System.out.println("start = " + start);
  51. }
  52. /**
  53. * 调用getAvailableBuffer取到一个可用的ByteBuffer,把数据填入ByteBuffer里,然后再调用writeBuffer把ByteBuffer写入解码器实例
  54. */
  55. public void framebuffer(){
  56. int i = 1;
  57. boolean reachEnd = false;
  58. while (!reachEnd){
  59. extractor.next();//下一帧
  60. ByteBuffer dstBuf = null;
  61. dstBuf = decoder.getAvailableBuffer(100000);
  62. if (dstBuf == null) {
  63. try {
  64. Thread.sleep(200);
  65. } catch (InterruptedException e) {
  66. System.out.println("InterruptedException");
  67. }
  68. continue;
  69. }
  70. System.out.println("02b dstBuf.toString() = " + dstBuf.toString());
  71. BufferInfo bufferInfo = new BufferInfo();
  72. bufferInfo.offset = 0;
  73. bufferInfo.size = extractor.readBuffer(dstBuf, 0);
  74. bufferInfo.timeStamp = extractor.getFrameTimestamp();
  75. bufferInfo.bufferType = extractor.getFrameType();
  76. System.out.println("bufferInfo bufferInfo = " + bufferInfo.timeStamp);
  77. reachEnd = extractor.getStreamId() == -1;
  78. System.out.println("reachEnd = " + reachEnd);
  79. if(reachEnd){
  80. bufferInfo.bufferType = bufferInfo.BUFFER_TYPE_END_OF_STREAM;
  81. }
  82. boolean ret = decoder.writeBuffer(dstBuf, bufferInfo);
  83. System.out.println("writeBuffer ret = " + ret);
  84. try {
  85. Thread.sleep(200);
  86. } catch (InterruptedException e) {
  87. System.out.println("InterruptedException");
  88. }
  89. }
  90. }
  91. /**
  92. * 停止解码,释放资源
  93. */
  94. public void stopAndRelease(){
  95. System.out.println("VedioDecoder stopAndRelease");
  96. decoder.stop();
  97. decoder.release();
  98. }

步骤2:封装writeFile方法,将获取到的buffer数据写入pcm文件中,此处com.harmonyospro.myapplication为工程bundleName,可替换为应用包名,代码如下:

  1. private void writeFile(ByteBuffer outputBuffer, BufferInfo info, int trackId) {
  2. FileOutputStream fileOutputStream = null;
  3. File fd = new File("/data/data/com.harmonyospro.myapplication/1.pcm");
  4. try {
  5. fileOutputStream = new FileOutputStream(fd, true);
  6. final byte[] chunk = new byte[info.size];
  7. outputBuffer.get(chunk);
  8. fileOutputStream.write(chunk, 0, outputBuffer.limit());
  9. outputBuffer.clear();
  10. } catch (FileNotFoundException e) {
  11. System.out.println("02b FileNotFoundException");
  12. } catch (IOException e) {
  13. System.out.println("02b IOException");
  14. }finally {
  15. try {
  16. fileOutputStream.close();
  17. } catch (IOException e) {
  18. System.out.println("IOException");
  19. }
  20. }
  21. }

步骤3:在需要调用视频提取音频的地方进行方法调用,代码如下:

  1. VideoDecoder videoDecoder = new VideoDecoder();
  2. videoDecoder.createDecoder();
  3. videoDecoder.start();
  4. videoDecoder.framebuffer();
  5. //vedioDecoder.stopAndRelease(); // 需要停止的时候停止

这里就完成从视频获取音频并保存到pcm文件的功能了,获取到pcm文件,就可以使用AudioRenderer进行播放了。

【参考文档】

视频编解码文档:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-video-codec-0000000000031749

媒体提取开发指导:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-video-extractor-0000000000044202

音频播放开发指导:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-audio-playback-0000000000031734

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/254494
推荐阅读
相关标签
  

闽ICP备14008679号