视频的「编解码」与「传输」的那些事儿
2017-11-24 00:00
316 查看
本文来自作者 Owen Chan 在 GitChat 上分享「关于视频的编解码与传输技术,你想知道的都在这里」,「阅读原文」查看交流实录
「文末高能」
编辑 | 泰龙
一、如何编译 FFmpag
准备工作
下载 FFmpeg 源码 :https://www.ffmpeg.org下载 NDK :http://developer.android.com/ndk/downloads/index.html
下载后文件在 Mac 中的存放路径如下:
ChendeMacBook-Pro: compileFF
ChendeMacBook−Pro:compileFFchenzongwen pwd
/Users/chenzongwen/compileFF //文件的存放路径 NDK 与FFmpeg 源码
如何编译 ffmpeg
首先进入 ffmpeg-3.0文件夹 ,在文件夹中增加 编译脚本 ffmpegConfig 文件如下图:ffmpegConfig 文件内容如下:
#!/bin/bash
NDK=/Users/chenzongwen/compileFF/android-ndk-r11b
export PATH=$PATH:$NDK
SYSROOT=$NDK/platforms/android-19/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
function build_one
{
bash ./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffserver \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--extra-libs=-lgcc \
--sysroot=$SYSROOT \
--enable-asm \
--enable-neon \
--extra-cflags="-O3 -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm -mfpu=neon"
build_one
~
~
然后在当前文件夹下执行如下命令:
chenzongwen. / ffmpegConfig
chenzongwen make -j4 //4 为 用4个 cup 进行编译
chenzongwen$ make install
命令执行完之后会在当前文件夹下生成一个 android 文件夹 android/arm 文件夹中的内容如下几个文件夹:
bin
include
lib
share
include 中存放的是头文件, lib 中存放的是 so 文件 整个编译过程结束 。
如何使用 FFmpeg
在跟 anroid-ndk-r11b ffmpeg-3.0 同级的目录下 创建 jni 文件夹 执行如下命令 :mkdir jni将之前编译的头文件(在 include 文件夹下)拷贝到 jni 文件夹下 并且在 jni 文件夹下创建 prbuilt 文件夹 并将之前生成的 so(在 lib 文件夹下)拷贝到 prebuilt 文件夹下, 拷贝完成后如下图:
ChendeMacBook-Pro:jni chenzongwen$ ls libavcodec libavdevice libavfilter libavformat libavutil libswresample libswscale prebuild ChendeMacBook-Pro:jni chenzongwen$ ls prebuild/ libavcodec-57.so libavfilter-6.so libavutil-55.so libswscale-4.so libavdevice-57.so libavformat-57.so libswresample-2.so libswscale.so
调用 so 方法 在当前文件夹下添加两个文件 Android.mk 和 Application.mk 内容分别如下
Android.mk 内容
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := avcodec-56-prebuilt LOCAL_SRC_FILES := prebuilt/libavcodec-57.so include $(PREBUILT_SHARED_LIBRARY) #include $(CLEAR_VARS) #LOCAL_MODULE := avdevice-56-prebuilt #LOCAL_SRC_FILES := prebuilt/libavdevice-57.so #include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avfilter-5-prebuilt LOCAL_SRC_FILES := prebuilt/libavfilter-6.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avformat-56-prebuilt LOCAL_SRC_FILES := prebuilt/libavformat-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avutil-54-prebuilt LOCAL_SRC_FILES := prebuilt/libavutil-55.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avswresample-1-prebuilt LOCAL_SRC_FILES := prebuilt/libswresample-2.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := swscale-3-prebuilt LOCAL_SRC_FILES := prebuilt/libswscale-4.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) Application.mk 的内容如下 : ChendeMacBook-Pro:jni chenzongwen$ vim Application.mk APP_ABI := armeabi #APP_ABI := armeabi-v7a APP_PLATFORM := android-10
编写调用文件 在当前文件夹下创建 **.c 文件 内容如下(文章结束会给出全部源码):
JNIEXPORT jint JNICALL Java_tan_h264_FFmpegNative_decode_1file
(JNIEnv *env, jobject obj, jstring filePath) { // jni 方法的定义
//todu
}
JNIEXPORT jint JNICALL Java_tan_h264_FFmpegNative_decodeFrame
(JNIEnv *env, jobject obj, jbyteArray in, jint inSize)
{
//todo
}
开始编译 在 jni 目录下执行:
ChendeMacBook-Pro:jni chenzongwen$ ../android-ndk-r11b/ndk-build
最后将 如下目录下的 so 拷贝到工程中就可以使用了。
ChendeMacBook-Pro:armeabi chenzongwen$ pwd
/Users/chenzongwen/compileFF/libs/armeabi
ChendeMacBook-Pro:armeabi chenzongwen$ ls
libavcodec-57.so libavutil-55.so libswscale-4.so
libavfilter-6.so libowenchan_Test.so
libavformat-57.so libswresample-2.so
ChendeMacBook-Pro:armeabi chenzongwen$
二、Android App 中如何调用 FFmpag so, jni 技术的讲解
java 层代码调用如下:import android.graphics.Bitmap;
import java.nio.ByteBuffer;
public class FFmpegNative {
static {
System.loadLibrary("avutil-54");
System.loadLibrary("swresample-1");
System.loadLibrary("avcodec-56");
System.loadLibrary("avformat-56");
System.loadLibrary("swscale-3");
System.loadLibrary("avfilter-5");
System.loadLibrary("avdevice-56");
System.loadLibrary("ffmpeg_codec");
}
public native int decode_init();
public native int decode_file(String filePath);
public native int decodeFrame(ByteBuffer in, int inSzie);
public native int decodeFrame2(ByteBuffer in, int inSzie);
public native int copyFrameRGB(ByteBuffer out);
public native int copyFrameYUV420p(ByteBuffer out);
public native int copyFrame2(ByteBuffer outY, ByteBuffer outU, ByteBuffer outV);
}
三、H264 格式
H.264分为两层
(一) H264 分为两层视频编码层 (VCL: Video Coding Layer): 进行视频编解码,包括运动补偿预 测,变换编码和熵编码等功能;
网络 取层 (NAL: Network Abstraction Layer): 用于采用适当的格式对VCL 视频数据进行封装打包;VCL需要打包成NAL,才能用于传输或存储.
(二)分层的目的
可以定义 VCL 视频压缩处理与 NAL 网络传输机制的接口,这样允许视频 编码层 VCL 的设计可以在不同的处理器平台进行移植,而与NAL层的数据封装格 式无关;
VCL 和 NAL 都被设计成工作于不同的传输环境,异构的网络环境并不需要 对 VCL 比特流进行重构和重编码。
(三)NALU 单元(NAL Unit)
H264 基本码流由一系列的 NALU 组成,组成结构如下
NALU: Coded H.264 data is stored or transmitted as a series of packets known as Network Abstraction LayerUnits. (NALU单元)
RBSP : A NALU contains a Raw Byte Sequence Payload, a sequence of bytes containing syntax elements.(原始数据字节流)
SODB:String Of Data Bits (原始数据比特流, 长度不一定是8的倍数,需要补齐)
Start code
一共有两种起始码:3字节的 0x000001 和4字节的 0x00000001;
如果 NALU 对应的 Slice 为一帧的开始,则用4字节表示,即 0x00000001;
否则用3字节 0x000001 表示,就是一个完整的帧被编为多个slice的时候,包含这些 slice 的 nalu 使用3字节起始码。
由于NAL的语法中没有给出长度信息,实际的传输、存储系统需要增加额外 的起始头实现各个 NAL 单元的定界。
先识别 H264 起始码 0x00000001;
接着读取NALU的header 字节,判断后 RBSP类型,相应的 六进制类 型定义如下:
0x67: SPS
0x68: PPS
0x65: IDR
0x61: non-IDR Slice 0x01: B Slice
0x06: SEI
0x09: AU Delimiter
从 读出的 个 H.264 视频帧以下 的形式存在: 0000000167… SPS
0000000168... PPS
00 00 00 01 65 ... IDR Slice
剩下的几个部分是视频的传输压缩与解压,我做 Chat 交流的时候对着代码来分析。
代码下载地址:https://github.com/chenzongwen/SimpleFFmpeg
界面如下:
近期热文
《手把手教你如何向
Linux 内核提交代码》
《Java
实现 Web 应用中的定时任务》
《沉迷前端,无法自拔的人,如何规划职业生涯?》
《TensorFlow
计算与智能基础》
《突破技术发展瓶颈、成功转型的重要因素》
《Selenium
爬取评论数据,就是这么简单!》
你和普通的程序员最大区别
在于
[b]「阅读原文」[/b]看交流实录,你想知道的都在这里
相关文章推荐
- 流媒体传输协议及音视频编解码技术
- 流媒体传输协议及音视频编解码技术
- 深入理解视频编解码技术----基于H.264标准及参考模型 读书笔记
- 基于RTP的h.264视频传输系统(二)
- H264 视频文件 帧格式 传输封装等 杂碎
- RTP/RTCP 视频数据传输 (续)
- mpeg4网络视频传输
- 基于RTP协议的H.264视频传输系统:实现
- 网络视频传输的服务质量(QoS)
- 使用Hive.js进行视频p2p传输遇到的问题记录
- udp 视频包网络传输花屏
- 数字视频网络传输层协议的选择
- 使用jrtplib传输H.264视频文件(3)
- 基于DirectShow的MPEG-4视频传输系统的研究与实现
- 摄像头视频采集压缩及传输
- 基于嵌入式Linux的视频图像采集与传输
- 使用jrtplib传输H.264视频文件(3)
- 流式传输 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 。 流式传输定义很广泛,现在主要指通过网络传送流媒体(如视频、音频)的技术总称。其特定含义为通过Internet 将影视节目传
- 基于RTP/RTCP的无线视频传输自适应带宽控制
- H.264视频编码传输的QoS特性分析(三)