| 名称 | 机构 | 推出时间 | 使用领域 |
| — | — | — | — |
| AAC | MPEG | 1997 | 各个领域 |
| AC-3 | Dolby | 1992 | 电影 |
| MP3 | MPEG | 1993 | 早期普及 |
| WMV | 微软 | 1999 | Windows |
音视频解码流程
-
解封装格式。将输入的按照一定格式封装的音视频数据,分离成为音频流压缩编码数据和视频流压缩编码数据。
-
解码。将视频和音频的压缩编码数据,解码成为非压缩的视频和音频原始数据。视频压缩数据通过解码输出为像素数据,如 YUV420P 、 RGB 等;音频压缩数据通过解码输出为非压缩的音频抽样数据,如 PCM 数据。
-
音视频同步。同步解码出来的视频和音频数据,并将音视频数据送至系统的声卡和显卡,播放和显示出来。
FFmpeg 函数库
FFmpeg 一般有 8 个函数库,各个函数库的功能如下:
| 函数库 | 功能 |
| — | — |
| avcodec | 音视频编解码 |
| avdevice | 多媒体设备输入输出 |
| avfilter | 滤镜特效 |
| avformat | 封装格式处理 |
| postproc | 后加工 |
| avutil | 工具库 |
| swresample | 音频采样数据格式转换 |
| swscale | 视频像素数据格式转换 |
FFmpeg 音视频解码
FFmpeg 音视频解码主要流程代码描述:
1. av_register_all() //注册组件
2. avformat_alloc_context //获取封装格式上下文
3. avformat_find_stream_info //获取输入文件信息
4. avcodec_find_decoder //获取解码器
5. avcodec_open2 //打开解码器
6. avcodec_decode_video2 或 avcodec_decode_audio4 //解码音视频帧
在 AS 工程中引入 FFmpeg 8 个动态库和 libyuv (负责视频像素数据格式转换)动态库。
工程的头文件目录:
工程的动态库目录:
Java 层 API :
package com.haohao.ffmpeg;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
import android.view.Surface;
/**
-
author: haohao
-
time: 2017/12/19
-
mail: haohaochang86@gmail.com
-
desc: AVUtils
*/
public class AVUtils {
private static final String TAG = “AVUtils”;
private static AVCallback AVCallback;
private static AVCallback sAVCallback;
public static void registerCallback(AVCallback callback) {
sAVCallback = callback;
}
static {
System.loadLibrary(“avfilter-5”);
System.loadLibrary(“avdevice-56”);
System.loadLibrary(“yuv”);
System.loadLibrary(“avutil-54”);
System.loadLibrary(“swresample-1”);
System.loadLibrary(“avcodec-56”);
System.loadLibrary(“avformat-56”);
System.loadLibrary(“swscale-3”);
System.loadLibrary(“postproc-53”);
System.loadLibrary(“native-lib”);
}
/**
-
解码视频中的视频压缩数据
-
@param input_file_path 输入的视频文件路径
-
@param output_file_path 视频压缩数据解码后输出的 YUV 文件路径
*/
public static native void videoDecode(String input_file_path, String output_file_path);
/**
-
显示视频视频解码后像素数据
-
@param input 输入的视频文件路径
-
@param surface 用于显示视频视频解码后的 RGBA 像素数据
*/
public static native void videoRender(String input, Surface surface);
/**
-
解码视频中的音频压缩数据
-
@param input 输入的视频文件路径
-
@param output 音频压缩数据解码后输出的 PCM 文件路径
*/
public static native void audioDecode(String input, String output);
/**
-
播放视频中的音频数据
-
@param input 输入的视频文件路径
*/
public static native void audioPlay(String input);
/**
- 创建一个 AudioTrack 对象,用于播放音频,在 Native 层中调用。
*/
public static AudioTrack createAudioTrack(int sampleRate, int num_channel) {
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
Log.i(TAG, “声道数:” + num_channel);
int channelConfig;
if (num_channel == 1) {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_MONO;
} else if (num_channel == 2) {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_STEREO;
} else {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_STEREO;
}
int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate, channelConfig,
audioFormat,
bufferSize, AudioTrack.MODE_STREAM);
return audioTrack;
}
public interface AVCallback {
void onFinish();
}
}
MySurfaceView.java
/**
-
author: haohao
-
time: 2017/12/20
-
mail: haohaochang86@gmail.com
-
desc: MySurfaceView
*/
public class MySurfaceView extends SurfaceView {
public MySurfaceView(Context context) {
super(context);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(){
// 设置像素绘制格式为 RGBA_8888
SurfaceHolder holder = getHolder();
holder.setFormat(PixelFormat.RGBA_8888);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<com.haohao.ffmpeg.MySurfaceView
android:id="@+id/my_surface_view"
android:layout_width=“match_parent”
android:layout_height=“match_p