FFmpeg初探

内容

  • 了解
  • 编译
  • 使用

FFmpeg

  1. 简介

FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序,它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的,而且还支持众多第三方库扩展。

详见wiki-FFmpeg

  1. 安装
brew install ffmpeg --with-ffplay
  1. 使用三件套
ffmpeg -i 1.mp4 //查看视频Meta信息
ffplay -ar 44100 -channels 2 -f s16le -i audiokits_decode.pcm //播放pcm
ffprobe -show_packets -of xml >packet_out.xml test.mp4 //查看帧信息(编码数据)
ffprobe -show_frames -of xml >packet_out.xml test.mp4 //查看帧信息(解码数据)

编译

  • 交叉编译
    是指在一个平台上(如PC)生成另外一个平台(Android/IOS等)的可执行程序。
  • 交叉编译工具链
    包含在NDK中,通过它PC便可以编译出能在Android上运行的程序。
    工具链通常包含以下部分:
    CC: 编译器,对C、C++源文件进行编译,生成汇编文件(指令助记符,汇编函数)
    AS: 翻译汇编文件成机器码,生成目标文件
    AR: 打包器,用于库操作
    LD:链接器,将多个目标文件链接成一个库或者可执行文件
    GDB: 调试工具
  • 编译三部曲
    很多知名开源库的编译步骤都是一样的,configure(配置) - make(编译) -make install(安装)。
    FDK-AAC 为例
    1. 先下载并解压源码
    2. 本机编译
      jackzhoudeMacBook-Pro:fdk-aac-0.1.5 jack.zhou$ pwd
      /Users/jack.zhou/Desktop/run_ffmpeg_bin/fdk-aac-0.1.5
      jackzhoudeMacBook-Pro:fdk-aac-0.1.5 jack.zhou$ ./configure --prefix=/Users/jack.zhou/Desktop/run_ffmpeg_bin/fdk-aac-0.1.5/out
      jackzhoudeMacBook-Pro:fdk-aac-0.1.5 jack.zhou$ make -j9
      jackzhoudeMacBook-Pro:fdk-aac-0.1.5 jack.zhou$ make install
      
    3. 产物
      在这里插入图片描述
  • 交叉编译
    交叉编译需要指定使用交叉编译工具链进行编译,才能编译出匹配目标平台的产物。交叉编译配置很多参数,通常使用shell脚本进行编译。例如交叉编译fdk-aac脚本如下:

    #!/bin/bash
    PROJECT_PATH=`pwd`
    NDK=/Users/jack.zhou/soft/android/ndk/android-ndk-r15c
    PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
    PLATFORM=$NDK/platforms/android-9/arch-arm
    export PATH=$PATH:$PREBUILT/bin:$PLATFORM/usr/include:
    
    export LDFLAGS="-L$PLATFORM/usr/lib -L$PREBUILT/arm-linux-androideabi/lib"
    export CFLAGS="-I$PLATFORM/usr/include  -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv7-a -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID  -Wa,--noexecstack -MMD -MP"
    
    export CPPFLAGS="$CFLAGS"
    export CFLAGS="$CFLAGS"
    export CXXFLAGS="$CFLAGS"
    export LDFLAGS="$LDFLAGS"
    
    export AS=$PREBUILT/bin/arm-linux-androideabi-as
    export LD=$PREBUILT/bin/arm-linux-androideabi-ld
    export CXX="$PREBUILT/bin/arm-linux-androideabi-g++ --sysroot=${PLATFORM}"
    export CC="$PREBUILT/bin/arm-linux-androideabi-gcc --sysroot=${PLATFORM}"
    export NM=$PREBUILT/bin/arm-linux-androideabi-nm
    export STRIP=$PREBUILT/bin/arm-linux-androideabi-strip
    export RANLIB=$PREBUILT/bin/arm-linux-androideabi-ranlib
    export AR=$PREBUILT/bin/arm-linux-androideabi-ar
    
    ./configure --host=armv7a \
    --enable-static \
    --disable-shared \
    --prefix=$PROJECT_PATH/output/armv7a/
    
    make clean
    make -j8
    make install 
    
  • 编译FFmpeg

    #!/bin/bash
    
    PROJECT_PATH=`pwd`
    CPU=arm
    cd ffmpeg-3.3.1
    
    export NDK=/Users/jack.zhou/soft/android/ndk/android-ndk-r15c
    export PLATFORM=$NDK/platforms/android-16/arch-arm/
    export PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
    export PREFIX=$PROJECT_PATH/output/android/$CPU
    # export OUT_STATIC_LIB_PATH=$PREFIX/lib
    
    ./configure \
    --prefix=$PREFIX \
    --target-os=linux \
    --arch=arm \
    --enable-gpl \
    --disable-shared \
    --disable-stripping \
    --enable-ffmpeg \
    --disable-ffplay \
    --disable-ffserver \
    --enable-ffprobe \
    --disable-avdevice \
    --disable-indevs \
    --disable-devices \
    --disable-debug \
    --disable-asm \
    --disable-yasm \
    --disable-doc \
    --disable-bsfs \
    --disable-indevs \
    --disable-outdevs \
    --enable-cross-compile \
    --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \
    --enable-filter=aresample \
    --enable-bsf=aac_adtstoasc \
    --enable-bsf=h264_mp4toannexb \
    --enable-small \
    --enable-dct \
    --enable-dwt \
    --enable-lsp \
    --enable-mdct \
    --enable-rdft \
    --enable-fft \
    --enable-static \
    --enable-version3 \
    --enable-nonfree \
    --disable-encoders \
    --enable-encoder=pcm_s16le \
    --enable-encoder=aac \
    --enable-encoder=libmp3lame \
    --enable-encoder=libfdk_aac \
    --enable-encoder=libx264 \
    --enable-encoder=mp2 \
    --disable-decoders \
    --enable-decoder=aac \
    --enable-decoder=mjpeg \
    --enable-decoder=png \
    --enable-decoder=gif \
    --enable-decoder=mp3 \
    --enable-decoder=h264 \
    --enable-decoder=pcm_s16le \
    --disable-parsers \
    --enable-parser=mjpeg  \
    --enable-parser=png  \
    --enable-parser=aac  \
    --enable-parser=h264  \
    --enable-parser=mpeg4video  \
    --enable-parser=mpegvideo  \
    --enable-parser=mpegaudio  \
    --disable-muxers \
    --enable-muxer=avi \
    --enable-muxer=flv \
    --enable-muxer=mp4 \
    --enable-muxer=m4v \
    --enable-muxer=mp3 \
    --enable-muxer=mov \
    --enable-muxer=h264 \
    --enable-muxer=wav \
    --enable-muxer=adts \
    --disable-demuxers \
    --enable-demuxer=mjpeg \
    --enable-demuxer=m4v \
    --enable-demuxer=gif \
    --enable-demuxer=mov \
    --enable-demuxer=avi \
    --enable-demuxer=flv \
    --enable-demuxer=h264 \
    --enable-demuxer=aac \
    --enable-demuxer=mp3 \
    --enable-demuxer=wav \
    --disable-protocols \
    --enable-protocol=rtmp \
    --enable-protocol=file \
    --enable-protocol=http \
    --disable-filters \
    --enable-filter=transpose \
    --enable-filter=crop \
    --enable-filter=vflip \
    --enable-filter=hflip \
    --enable-libx264 \
    --enable-libfdk_aac \
    --enable-libmp3lame \
    --sysroot=$PLATFORM \
    --extra-cflags="-marm -march=armv7-a -I$PLATFORM/usr/include -Iexternal_libs/fdk-aac/output/armv7a/include -Iexternal_libs/libx264/output/armv7a/include -Iexternal_libs/lame/output/armv7a/include" \
    --extra-ldflags="-marm -march=armv7-a -Lexternal_libs/fdk-aac/output/armv7a/lib -Lexternal_libs/libx264/output/armv7a/lib -Lexternal_libs/lame/output/armv7a/lib"
    
    make -j6
    make install
    

    脚本已上传 compile-ffmpeg

使用

1. 命令行
  1. 通过可执行文件 FFmpegBox
    修改编译脚本,编译出ffmpeg/ffprobe
    放在assets目录,运行命令前拷贝到手机目录
    runtime执行ffmpeg命令,调用对应的可执行文件
  2. 通过命令行入口函数
    ffmpeg是由ffmpeg.c编译而来,修改ffmpeg.c提供命令入口
    Android 集成 FFmpeg (二) 以命令方式调用 FFmpeg
    Android 集成 FFmpeg (三) 获取 FFmpeg 执行进度
2. api
  • Examples
  • 结构体
    FFMPEG有几个最重要的结构体,包含了解协议,解封装,解码操作
    • AVFormatContext
      贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。下面看几个主要变量的作用(在这里考虑解码的情况):
      struct AVInputFormat *iformat:输入数据的封装格式
      AVIOContext *pb:输入数据的缓存
      unsigned int nb_streams:视音频流的个数
      AVStream **streams:视音频流
      char filename[1024]:文件名
      int64_t duration:时长(单位:微秒us,转换为秒需要除以1000000)
      int bit_rate:比特率(单位bps,转换为kbps需要除以1000)
      AVDictionary *metadata:元数据
      
    • AVStream
      存储每一个视频/音频流信息的结构体. AVStream重要的变量如下所示:
      int index:标识该视频/音频流
      AVCodecContext *codec:指向该视频/音频流的AVCodecContext(它们是一一对应的关系)
      AVRational time_base:时基。通过该值可以把PTS,DTS转化为真正的时间。FFMPEG其他结构体中也有这个字段,但是根据我的经验,只有AVStream中的time_base是可用的。PTS*time_base=真正的时间
      int64_t duration:该视频/音频流长度
      AVDictionary *metadata:元数据信息
      AVRational avg_frame_rate:帧率(注:对视频来说,这个挺重要的)
      
    • AVCodecContext
      编解码器上下文,列举部分重要变量:
      enum AVMediaType codec_type:编解码器的类型(视频,音频...)
      struct AVCodec  *codec:采用的解码器AVCodec(H.264,MPEG2...)
      int bit_rate:平均比特率
      uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
      AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)
      int width, height:如果是视频的话,代表宽和高
      int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
      int sample_rate:采样率(音频)
      int channels:声道数(音频)
      enum AVSampleFormat sample_fmt:采样格式
      int profile:型(H.264里面就有,其他编码标准应该也有)
      int level:级(和profile差不太多)
      
    • AVCodec
      存储编解码器信息,列举部分变量:
      const char *name:编解码器的名字,比较短
      const char *long_name:编解码器的名字,全称,比较长
      enum AVMediaType type:指明了类型,是视频,音频,还是字幕
      enum AVCodecID id:ID,不重复
      const AVRational *supported_framerates:支持的帧率(仅视频)
      const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
      const int *supported_samplerates:支持的采样率(仅音频)
      const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
      const uint64_t *channel_layouts:支持的声道数(仅音频)
      int priv_data_size:私有数据的大小
      
      • AVPacket
        存储压缩编码数据相关信息的结构体。
      uint8_t *data:压缩编码的数据。
      例如对于H.264来说。1个AVPacket的data通常对应一个NAL。
      注意:在这里只是对应,而不是一模一样。他们之间有微小的差别:使用FFMPEG类库分离出多媒体文件中的H.264码流
      因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。
      int   size:data的大小
      int64_t pts:显示时间戳
      int64_t dts:解码时间戳
      int   stream_index:标识该AVPacket所属的视频/音频流。
      
      • AVFrame
        存储解码之后的原始数据,即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM
      uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)
      int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。
      int width, height:视频帧宽和高(1920x1080,1280x720...)
      int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
      int format:解码后原始数据类型(YUV420,YUV422,RGB24...)
      int key_frame:是否是关键帧
      enum AVPictureType pict_type:帧类型(I,B,P...)
      AVRational sample_aspect_ratio:宽高比(16:9,4:3...)
      int64_t pts:显示时间戳
      int coded_picture_number:编码帧序号
      
  • 函数
    av_register_all():注册所有组件
    avformat_open_input():打开输入视频文件
    avformat_find_stream_info():获取视频文件信息
    avcodec_find_decoder():查找解码器
    avcodec_open1():打开解码器
    av_read_frame():从输入文件读取一帧压缩数据
    avcodec_decode_video2():解码一桢压缩数据
    avcodec_close():关闭解码器
    avformat_close_input():关闭输入视频文件
  • JNI
  • Demo
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值