Android音视频编码(3)

继续Android音视频编码(2)中的内容,在上一篇文章中,对视频解码和编码进行了详细的介绍,具体可参见这里。

视频解码 Surface播放

    @Overridepublic void start(){super.start();mediaCodec.setCallback(new MediaCodec.Callback() {@Overridepublic void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);int size = extractor.readBuffer(inputBuffer, true);long st = extractor.getSampleTime();if (size >= 0) {codec.queueInputBuffer(index,0,size,st,extractor.getSampleFlags());} else {//结束codec.queueInputBuffer(index,0,0,0,BUFFER_FLAG_END_OF_STREAM);}}@Overridepublic void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
...}@Overridepublic void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {codec.stop();}@Overridepublic void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {}});mediaCodec.configure(mediaFormat,mSurface,null,0);//mediaCodec.configure(mediaFormat,null,null,0);mediaCodec.start();}

通过这行 mediaCodec.configure(mediaFormat,mSurface,null,0)代码就可以将解码后的数据在相应的surface中进行预览播放。

音频解码

这里是音频解码的参考代码。

package com.example.myapplication.media.codec.async;import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Message;
import android.util.Log;import androidx.annotation.NonNull;import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;/*** describe:*/
public class AsyncAudioDecode extends BaseAsyncDecode {private static final String TAG = "AsyncAudioDecode";private int mPcmEncode;//一帧的最小buffer大小private  int mMinBufferSize;private AudioTrack mAudioTrack;public AsyncAudioDecode(long progress) {super(progress);//拿到采样率if (mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) {mPcmEncode = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);} else {//默认采样率为 16bitmPcmEncode = AudioFormat.ENCODING_PCM_16BIT;}//音频采样率int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);//获取视频通道数int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);//拿到声道int channelConfig = channelCount == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO;mMinBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, mPcmEncode);/*** 设置音频信息属性* 1.设置支持多媒体属性,比如audio,video* 2.设置音频格式,比如 music*/AudioAttributes attributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();/*** 设置音频数据* 1. 设置采样率* 2. 设置采样位数* 3. 设置声道*/AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate).setEncoding(AudioFormat.ENCODING_PCM_16BIT).setChannelMask(channelConfig).build();//配置 audioTrack,采用流模式mAudioTrack = new AudioTrack(attributes,format,mMinBufferSize,AudioTrack.MODE_STREAM,AudioManager.AUDIO_SESSION_ID_GENERATE);//监听播放mAudioTrack.play();}@Overridepublic void start(){super.start();mediaCodec.setCallback(new MediaCodec.Callback() {@Overridepublic void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);int size = extractor.readBuffer(inputBuffer, false);if (size >= 0) {codec.queueInputBuffer(index,0,size,extractor.getSampleTime(),extractor.getSampleFlags());} else {//结束codec.queueInputBuffer(index,0,0,0,MediaCodec.BUFFER_FLAG_END_OF_STREAM);}}@Overridepublic void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {Message msg = new Message();msg.what = MSG_AUDIO_OUTPUT;msg.arg1 = index;msg.arg2 = info.size;mHandler.sendMessage(msg);}@Overridepublic void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {codec.stop();}@Overridepublic void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {}});mediaCodec.configure(mediaFormat, null, null, 0);mediaCodec.start();}@Overridepublic boolean handleMessage(@NonNull Message msg) {switch (msg.what){case MSG_AUDIO_OUTPUT:int index = msg.arg1;int size = msg.arg2;ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(index);try {if (outputBuffer != null) {mAudioTrack.write(outputBuffer, size,AudioTrack.WRITE_BLOCKING);mediaCodec.releaseOutputBuffer(index, false);}} catch (Exception e) {e.printStackTrace();}break;default:break;}return super.handleMessage(msg);}@Overridepublic void stop() {super.stop();//释放 AudioTrackif (mAudioTrack.getState() != AudioTrack.STATE_UNINITIALIZED) {try {mAudioTrack.stop();}catch (Exception e){}}}@Overridepublic void release() {super.release();mAudioTrack.release();}@Overrideprotected int decodeType() {return AUDIO;}
}

由于这个例子不需要对音频进行解码。这里直接使用。可参考则这段代码,先添加音频轨道,然后读取音频数据到buffer中,最后通过mediaMuxer将音频混合到视频当中。

    @SuppressLint("WrongConstant")public void encodeAudio() {MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);if (audioFormat != null) {//写完视频,再把音频混合进去int audioSize = 0;//读取音频帧的数据,直到结束while ((audioSize = audioExtractor.readBuffer(buffer, false)) > 0) {bufferInfo.offset = 0;bufferInfo.size = audioSize;bufferInfo.presentationTimeUs = audioExtractor.getSampleTime();bufferInfo.flags = audioExtractor.getSampleFlags();mediaMuxer.writeSampleData(audioTrack, buffer, bufferInfo);}}}

更多内容,欢迎关注我的微信公众号:半夏之夜的无情剑客。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/637877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0121-1-计算机网络安全

计算机网络安全 1.Get 和 Post 的区别 结构:get 有请求体,post没有请求体 应用场景:get 用于获取数据,post用于提交数据; 缓存:get 的缓存保存在浏览器和web服务器日志中; 传输方式&#x…

Centos使用Docker搭建自己的Gitlab(社区版和设置汉化、修改密码、设置SSH秘钥、添加拉取命令端口号)

根据我的经验 部署Gitlab(社区版) 至少需要2核4g的服务器 带宽3~4M 1. 在自己电脑上安装终端:宝塔ssl终端 或者 FinalShell,根据喜好安装即可 http://www.hostbuf.com/t/988.html http://www.hostbuf.com/downloads/finalshell_w…

基于OpenSSL的SSL/TLS加密套件全解析

概述 SSL/TLS握手时,客户端与服务端协商加密套件是很重要的一个步骤,协商出加密套件后才能继续完成后续的握手和加密通信。而现在SSL/TLS协议通信的实现,基本都是通过OpenSSL开源库,本文章就主要介绍下加密套件的含义以及如何在O…

LC 对角线遍历

LC 对角线遍历 题目描述: 给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。 题目实例: 示例一: 输入:mat [[1,2,3],[4,5,6],[7,8,9]] 输出:[…

kotlin map 与 flatmap

kotlin map 与 flatmap 是2个不同的概念的 map 是一种数据结构,flatmap 是一个高阶函数,处理集合用的 Map Map 是一种数据结构,它由一系列的键值对组成,每个键都是唯一的,并且与一个特定的值相关联。你可以通过键来…

前后置、断言、提取变量、数据库操作功能

前置操作和后置操作都是 API 请求在发送和响应过程中执行的脚本,主要用于在发起 API 请求前和获得响应后完成验证或执行某些操作,目的是为了提高 API 调试和测试的效率,并确保接口的正确性。 前置操作​ 前置操作是在 API 请求之前执行的脚本…

Redis(五)

1、布隆过滤 1.1、简介 由一个初值都为零的bit数组和多个哈希函数构成,可以用来快速判断集合中是否存在某个元素,减少占用内存,不保存数据信息,只是在内存中做出一个标记。 它实际上是一个很长的二进制数组(00000000)一系列随机h…

【数据结构与算法】归并排序详解:归并排序算法,归并排序非递归实现

一、归并排序 归并排序是一种经典的排序算法,它使用了分治法的思想。下面是归并排序的算法思想: 递归地将数组划分成较小的子数组,直到每个子数组的长度为1或者0。将相邻的子数组合并,形成更大的已排序的数组,直到最…

OpenCV读取摄像头窗口变大且很卡的解决方法

视频讲解 OpenCV读取摄像头窗口变大且很卡的解决方法 测试过程 读取摄像头窗口变大且很卡的代码 import cv2 cap cv2.VideoCapture(0) if not cap.isOpened():print("Cannot open camera")exit() while True:ret, frame cap.read()if not ret:print("no str…

Arduino开发实例-SDS011粉尘检测传感器驱动

SDS011粉尘检测传感器驱动 文章目录 SDS011粉尘检测传感器驱动1、SDS011介绍2、硬件准备及接线3、代码实现在本文中,将介绍如何使用 Arduino 动粉尘传感器 SDS011 制作空气质量监测系统。 1、SDS011介绍 粉尘本身根据它们的大小分为两类。 直径在2.5至10微米之间的称为粗颗粒…

2677. 分块数组

说在前面 🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。 题目描述 给定一个数组 arr 和一个块大小 size ,返回一个 分块 的数组。分块 的数组包含了…

Linux系统OpenGL安装

安装OpenGL 1、安装OpenGL Library sudo apt-get install libgl1-mesa-dev 2、安装OpenGL Utilities OpenGL Utilities 是一组建构于 OpenGL Library 之上的工具组,提供许多很方便的函式,使 OpenGL 更强大且更容易使用 sudo apt-get install libglu1…

conda install命令无法安装pytorch

由于网络问题,直接采用conda install命令可能无法直接下载对应的cuda包。 方法一:采用pip命令替代 步骤1:切换pip的源为国内源: 若只是临时切换: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-p…

SpringMVC-.xml的配置

文章目录 一、对pom.xml的配置二、对web.xml1.第一种方式2. 第二种方式 三、对SpringMVC.xml的配置 一、对pom.xml的配置 <!-- 打包成war包--><packaging>war</packaging> <dependencies><!-- SpringMVC--><dependency><gro…

Minio文件分片上传实现

资源准备 MacM1Pro 安装Parallels19.1.0请参考 https://blog.csdn.net/qq_41594280/article/details/135420241 MacM1Pro Parallels安装CentOS7.9请参考 https://blog.csdn.net/qq_41594280/article/details/135420461 部署Minio和整合SpringBoot请参考 https://blog.csdn.net/…

k8s-ingress一

Comfigmap&#xff1a;存储数据 Date&#xff1a; Key&#xff1a;value 挂载的方式&#xff0c;把配置信息传给容器 生产当中的yml文件很长&#xff1a; 有deployment 容器的探针 资源限制 Configmap 存储卷 Service Ingress K8s的对外服务&#xff0c;ingress Se…

【Linux学习】进程信号

目录 十七.进程信号 导言 17.1 linux中的信号列表 17.2 标准信号与实时信号 17.3 信号的产生 17.3.1 通过终端按键产生信号 17.3.2 调用系统函数产生信号 17.3.3 软件条件产生信号 17.3.4 硬件异常产生信号 17.3.5 【补充】核心转储 Core Dump 17.4 信号的阻塞 17.4.1 信号相关…

将字符串中可能被视为正则表达式的特殊字符进行转义re.escape()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将字符串中可能被视为 正则表达式的特殊字符 进行转义 re.escape() [太阳]选择题 请问以下代码最后输出的结果是&#xff1f; import re s [a-z] print("【显示】s ",s) print(&q…

python24.1.21面向对象编程

面向对象编程&#xff1a;创建对象&#xff0c;定义对象的方法和属性 封装&#xff1a;隐藏内部实现细节&#xff0c;只通过外部接口访问使用 继承&#xff1a;允许创建有层次的类&#xff08;子类&#xff0c;父类&#xff09; 多态&#xff1a;同样接口&#xff0c;对象具体…

JVM:Java类加载机制

Java类加载机制的全过程&#xff1a; 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的&#xff0c;类型的加载过程必须按照这种顺序按部就班地开始&#xff0c;而解析阶段则不一定&#xff1a;它在某些情况下可以在初始化阶段之后再开始&#xff0c; 这是为了支持Java…