FFmpeg 之音视频解码与音视频同步(二),flutterplugin开发

本文详细介绍了使用FFmpeg进行音视频解码的过程,包括解封装、解码、音视频同步等步骤。同时,展示了在Android项目中如何引入FFmpeg库,以及如何在FlutterPlugin中实现音视频的解码和播放。通过示例代码,演示了如何处理音视频帧并将其渲染到SurfaceView上,以及如何播放解码后的音频数据。
摘要由CSDN通过智能技术生成

| 名称 | 机构 | 推出时间 | 使用领域 |

| — | — | — | — |

| AAC | MPEG | 1997 | 各个领域 |

| AC-3 | Dolby | 1992 | 电影 |

| MP3 | MPEG | 1993 | 早期普及 |

| WMV | 微软 | 1999 | Windows |

音视频解码流程


3239933-075669d44815489b.png

  1. 解封装格式。将输入的按照一定格式封装的音视频数据,分离成为音频流压缩编码数据和视频流压缩编码数据。

  2. 解码。将视频和音频的压缩编码数据,解码成为非压缩的视频和音频原始数据。视频压缩数据通过解码输出为像素数据,如 YUV420P 、 RGB 等;音频压缩数据通过解码输出为非压缩的音频抽样数据,如 PCM 数据。

  3. 音视频同步。同步解码出来的视频和音频数据,并将音视频数据送至系统的声卡和显卡,播放和显示出来。

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 (负责视频像素数据格式转换)动态库。

工程的头文件目录:

3239933-5160f0db0049e69d.png

工程的动态库目录:

3239933-5160f0db0049e69d.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值