赞
踩
【关键字】
视频提取类Extractor、视频编解码、保存pcm文件
【写在前面】
在使用API6开发HarmonyOS应用时,通常会开发一些音视频媒体功能,这里介绍如何从视频中提取音频保存到pcm文件功能,生成pcm音频文件后,就可使用音频播放类AudioRenderer进行播放了。这里主要介绍从视频提取音频并保存到pcm文件的开发步骤。
【开发步骤】
步骤1:对视频格式的文件进行提取音频文件,并通过解码器解码并监听获取到的buffer数据;直接使用Extractor从视频中提取出来的音频数据不能直接作为类似pcm数据源进行播放,需要使用解码器解码之后得到的原始数据才可AudioRenderer进行播放。新建VideoDecoder类,在里面封装相关功能代码。使用Extractor从视频提取音频数据并使用解码器解码,代码如下:
- // 可创建VideoDecoder类,实现相关功能
- private Format format;
- private Codec decoder;
- private Extractor extractor;
-
- public void createDecoder() {
- decoder = Codec.createDecoder(); // 创建解码器
- extractor = new Extractor(); // 创建Extractor解封装类
- boolean ret = extractor.setSource(new Source("/data/data/com.harmonyospro.myapplication/vedio_audio_test.mp4")); // 设置数据源,com.harmonyospro.myapplication为应用包名;也可设置为网络视频数据源
- System.out.println("setSource ret = " + ret);
- int trackCount = extractor.getTotalStreams();//获取轨道
- for (int i = 0; i < trackCount; i++) {
- format = extractor.getStreamFormat(i);
- if (format.getStringValue("mime").contains("audio")) { // 视频video,audio音频
- /**
- * @tc.steps: step2.set codec format for decoder
- * @tc.expected: step2.the return value is true
- */
- ret = decoder.setCodecFormat(format);
- System.out.println("setCodecFormat ret = " + ret);
- ret = extractor.specifyStream(i);
- System.out.println("specifyStream ret = " + ret);
- System.out.println("format.toString() = " + format.toString());
- System.out.println("format.getStringValue(mine) = "+format.getStringValue("mime"));
- System.out.println("format.getStringValue(width) = "+format.getIntValue("width"));
- System.out.println("format.getStringValue(height) = "+format.getIntValue("height"));
- break;
- }
- }
- decoder.registerCodecListener(listener);
- }
-
- Codec.ICodecListener listener = new Codec.ICodecListener() {
- @Override
- public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int i) {
- Format fmt = decoder.getBufferFormat(byteBuffer);
- System.out.println("fmt.toString() = " + fmt.toString());
- // 写入文件
- writeFile(byteBuffer,bufferInfo,i);
- System.out.println("onReadBuffer == " + bufferInfo.toString());
- }
-
- @Override
- public void onError(int errorCode, int act, int trackId) {
- throw new RuntimeException();
- }
- };
-
- /**
- * 调用 start()方法开始解码
- */
- public void start(){
- boolean start = decoder.start();
- System.out.println("start = " + start);
- }
-
- /**
- * 调用getAvailableBuffer取到一个可用的ByteBuffer,把数据填入ByteBuffer里,然后再调用writeBuffer把ByteBuffer写入解码器实例
- */
- public void framebuffer(){
- int i = 1;
- boolean reachEnd = false;
- while (!reachEnd){
- extractor.next();//下一帧
- ByteBuffer dstBuf = null;
- dstBuf = decoder.getAvailableBuffer(100000);
-
- if (dstBuf == null) {
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- System.out.println("InterruptedException");
- }
- continue;
- }
- System.out.println("02b dstBuf.toString() = " + dstBuf.toString());
- BufferInfo bufferInfo = new BufferInfo();
- bufferInfo.offset = 0;
- bufferInfo.size = extractor.readBuffer(dstBuf, 0);
- bufferInfo.timeStamp = extractor.getFrameTimestamp();
- bufferInfo.bufferType = extractor.getFrameType();
- System.out.println("bufferInfo bufferInfo = " + bufferInfo.timeStamp);
- reachEnd = extractor.getStreamId() == -1;
- System.out.println("reachEnd = " + reachEnd);
- if(reachEnd){
- bufferInfo.bufferType = bufferInfo.BUFFER_TYPE_END_OF_STREAM;
- }
- boolean ret = decoder.writeBuffer(dstBuf, bufferInfo);
- System.out.println("writeBuffer ret = " + ret);
-
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- System.out.println("InterruptedException");
- }
- }
- }
-
- /**
- * 停止解码,释放资源
- */
- public void stopAndRelease(){
- System.out.println("VedioDecoder stopAndRelease");
- decoder.stop();
- decoder.release();
- }

步骤2:封装writeFile方法,将获取到的buffer数据写入pcm文件中,此处com.harmonyospro.myapplication为工程bundleName,可替换为应用包名,代码如下:
- private void writeFile(ByteBuffer outputBuffer, BufferInfo info, int trackId) {
- FileOutputStream fileOutputStream = null;
- File fd = new File("/data/data/com.harmonyospro.myapplication/1.pcm");
- try {
- fileOutputStream = new FileOutputStream(fd, true);
- final byte[] chunk = new byte[info.size];
- outputBuffer.get(chunk);
- fileOutputStream.write(chunk, 0, outputBuffer.limit());
- outputBuffer.clear();
- } catch (FileNotFoundException e) {
- System.out.println("02b FileNotFoundException");
- } catch (IOException e) {
- System.out.println("02b IOException");
- }finally {
- try {
- fileOutputStream.close();
- } catch (IOException e) {
- System.out.println("IOException");
- }
- }
- }

步骤3:在需要调用视频提取音频的地方进行方法调用,代码如下:
- VideoDecoder videoDecoder = new VideoDecoder();
- videoDecoder.createDecoder();
- videoDecoder.start();
- videoDecoder.framebuffer();
- //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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。