FFMPEG学习第三篇--编译x264并使用x264压缩视频

一:编码介绍

软编码:使用cpu进行编码。
硬编码:使用显卡GPU专用的DSP\FPGA\ASIC芯片等硬件进行编码。
软编码的特点是升级方便,实现简单,但是cpu负载中,性能低。硬编码性能高。

在H.265之前,H.264一直是新一代的编码标准。H265主要是用来满足4
k,8k视频的需求,H.264以高压缩高质量和支持多种网络流媒体传输而闻名。经过h264标准对视频进行压缩编码,能够有效减小视频的文件大小,这主要是受益于他的低码率。与MPEG-2和MPEG-4 ASP等压缩技术相比,H.264压缩技术节省来用户的下载时间和流量。

H.264只是一个标准,具体实现包括JM,T264,x264。而由于种种原因,JM,T264等实现工具,并不能很好地继续完成我们的需求,因此x264便成了互联网世界中主流的实现H.264标准的编码工具。

FFMPEG默认只支持对H.264的解码,并不支持对H.264的编码,因此就需要我们手动配置FFMPEG来实现对H.264的编码。首先我们需要下载x264

二:编译x264

下载完成之后,我们需要首先编译x264为静态库,这是因为FFMPEG默认是通过静态链接方式来链接其他功能库。我们在编译ffmpeg时,修改了configure文件,这样方便生成可以让android识别的*.so文件,但是我们编译x264是生成的静态库,因此不需要修改x264的configure文件。下面我们直接放一个网上的编译脚本,build_x264_arm.sh:

#!/bin/bash

NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64

CPU=arm
PREFIX=/Users/xiaguangcheng/x264/arm
ADDI_CFLAGS=""
ADDI_LDFLAGS=""

function build_x264
{
./configure \
    --prefix=$PREFIX \
    --disable-shared \
    --disable-asm \
    --enable-static \
    --enable-pic \
    --enable-strip \
    --host=arm-linux-androideabi \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --sysroot=$SYSROOT
    --extra-cflags="-Os -fpic $ADDI_CFLAGS $OPTIMIZE_CFLAGS" \
    --extra-ldflags="$ADDI_LDFLAGS" \
    $ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
}


build_x264

下面的几行需要根据你的电脑来完成配置。同时在x264文件夹下新建一个arm的文件夹用来存放编译之后的文件。

NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/x264/arm

接着我们通过命令cd x264进入到x264文件夹内,查看新建的build_x264_arm.sh文件的权限

ls -l build_x264_arm.sh
-rwxrwxrwx  1 xiaguangcheng  staff  733  6 26 20:46 build_x264_arm.sh

如果你的该文件不具备可执行权限,那么就需要手动添加可执行权限,添加完权限之后,记得再查看一下是否成功。

chmod 777 build_x264_arm.sh
ls -l build_x264_arm.sh

如果还没有安装yasm那么可以通过homebrew安装

brew install yasm

否则可能会报一个错误

if you really want to compile without asm, configure with --disable-asm. make: *** [config.mak] Error 1 Makefile:3: config.mak: No such file or directory

接下来我们在命令行中就可以运行该文件进行编译

./build_x264_arm.sh

待编译结束后,我们在刚刚创建的arm文件夹中的就可以找到一个.a静态库。


image.png

三:编译含有x264静态库的ffmpeg动态库

第一篇中我们讲解来如何编译一个ffmpeg动态库,但是那个动态库并没有包含x264,这里我们将x264包含进来。因此在编译ffmpeg动态库的编译文件基础之上进行略微的修改即可,buildffmpeg.sh文件内容更新如下:

#!/bin/bash
export TMPDIR=/Users/xiaguangcheng/ffmpeg/ffmpeg/ffmpegtemp
NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/ffmpeg/ffmpeg/android
ADDI_CFLAGS="-marm"

function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-gpl \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-libx264 \
--enable-yasm \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-I/Users/xiaguangcheng/x264/arm/include" \
--extra-ldflags="-L/Users/xiaguangcheng/x264/arm/lib" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_one

主要修改包括以下几点

--enable-gpl \
--enable-libx264 \
--enable-yasm \
--extra-cflags="-I/Users/xiaguangcheng/x264/arm/include" \
--extra-ldflags="-L/Users/xiaguangcheng/x264/arm/lib" \
  • -I:编译阶段生效的参数,用于指定头文件的搜索路径。
  • -L:链接阶段生效的参数,用于指定链接库的搜索路径,-l用于指定链接库的名称,一般两者一起使用的话,就可以指定动态链接库。

查看该文件是否有执行权限,如果有执行权限

./buildffmpeg.sh

运行该命令后即可得到最终的包含x264的ffmpeg的so动态库。我们也可以通过在编译过程中打印的日志来查看

image.png

四:使用包含x264的ffmpeg动态库在android中压缩视频

在android中使用ffmpeg执行命令,并通过命令来编码压缩视频,利用FFmpeg玩转Android视频录制与压缩(一),这篇博客已经说的差不多了,但是根据我们项目中上传视频的需求,我们还需要获取在编码压缩过程中的进度,具体思路是通过process来执行命令,而不是通过jni调用ffmpeg来执行命令。而上面提到的这篇博客就是通过jni调用ffmpeg来执行命令的。通过android.jar中的Process来执行命令,可以获取到执行命令的结果,由于在执行ffmpeg的过程中,会出现诸如下面这样的结果输出

frame=  125 fps=0.0 q=38.0 size=     176kB time=00:00:08.54 bitrate= 168.7kbits/frame=  298 fps=297 q=35.0 size=     471kB time=00:00:20.03 bitrate= 192.6kbits/frame=  454 fps=302 q=35.0 size=     727kB time=00:00:30.46 bitrate= 195.4kbits/frame=  662 fps=331 q=33.0 size=    1067kB time=00:00:44.37 bitrate= 197.0kbits/frame=  853 fps=341 q=36.0 size=    1386kB time=00:00:57.05 bitrate= 199.0kbits/frame= 1041 fps=347 q=37.0 size=    1719kB time=00:01:09.56 bitrate= 202.4kbits/frame= 1241 fps=354 q=37.0 size=    2063kB time=00:01:22.91 bitrate= 203.8kbits/frame= 1478 fps=369 q=37.0 size=    2475kB time=00:01:38.73 bitrate= 205.3kbits/frame= 1677 fps=372 q=38.0 size=    2815kB time=00:01:51.96 bitrate= 206.0kbits/frame= 1889 fps=378 q=38.0 size=    3181kB time=00:02:06.13 bitrate= 206.6kbits/frame= 2101 fps=382 q=36.0 size=    3535kB time=00:02:20.29 bitrate= 206.4kbits/frame= 2341 fps=390 q=32.0 size=    3931kB time=00:02:36.22 bitrate= 206.1kbits/frame= 2602 fps=400 q=36.0 size=    4393kB time=00:02:53.63 bitrate= 207.3kbits/frame= 2809 fps=401 q=27.0 size=    4728kB time=00:03:07.47 bitrate= 206.6kbits/frame= 3016 fps=406 q=-1.0 Lsize=    5098kB time=00:03:21.01 bitrate= 207.7kbits/s speed=  27x    

那么我们就可以通过先获取本地视频的时长,然后再拿到输出结果中的转换时长来查看编码进度。上面输出中的size并不是原视频的size,而是编码之后的新视频已经生成的size,因此不可以参考。但是我们编码只是压缩了大小,并没有改变时长,因此时间可以用来参考
1:获取本地视频时长

Cursor mCursor = mContentResolver.query(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                null, null, null,
                MediaStore.MediaColumns.DATE_ADDED + " DESC");
            int columnIndex1 = mCursor.getColumnIndex(MediaStore.Video.Media.DURATION);
long millSeconds = mCursor.getLong(columnIndex1);

2:获取ffmpeg命令输出结果

String [] cmd =new String []{"ffmpeg","-i","xiaugangcheng.mp4","xia.mp4"};
Process process = new ProcessBuilder()
       .command(cmd)
       .redirectErrorStream(true)
       .start();
   try {
     InputStream in = process.getInputStream();
     OutputStream out = process.getOutputStream();
     readStream(in);

    } finally {
     process.destroy();
   }

3:根据输出结果获取已转换的视频时长

                    String s=""frame=125 fps=0.0 q=38.0 size=176kB time=01:11:08.54 bitrate= 168.7kbits"";
                    int index = s.indexOf("time=");
                    if(index==-1){
                        return;
                    }
                    if(index+5>s.length()||index+13>s.length()){
                        return;
                    }
                    String cmd = s.substring(index+5, index+13);
                    System.out.println(cmd);

                    String[] my =cmd.split(":");
                    int hour =Integer.parseInt(my[0]);
                    int min =Integer.parseInt(my[1]);
                    int sec =Integer.parseInt(my[2]);

                    int totalSec =hour*3600+min*60+sec;
                    int percent =String totalSec *100/ 202;
                    progressDialog.setMessage("Processing\n"+percent+"%");

拿到输入输出流,就可以转化为string来提取时间了

文章参考
初识FFmpeg编译那些事
Mac下为Android编译FFMPEG和x264
在Android上使用FFmpeg压缩视频
编译Android下可执行命令的FFmpeg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 前几天项目需要压缩视频,Github上找了许多库,要么就是太大,要么就是质量不高,其实我只需要压缩视频,最好的方案...
    voiddog阅读 26,184评论 59 82
  • 原文地址:http://blog.csdn.net/yipie/article/details/7912291 摘...
    冬的天阅读 7,159评论 1 6
  • FFmpeg X264编码参数 目录 码率控制 1 X264的preset和tune 2 编码延时建议...
    古则阅读 29,642评论 1 15
  • 0 概述 FFmpeg是一套领先的音视频多媒体处理开源框架,采用LGPL或GPL许可证。它提供了对音视频的采集、编...
    但行耕者阅读 6,784评论 0 19
  • 文/十月云 楼下卖豆浆的小伙子 一个人 一张课桌 一个保温箱 矮个子 暗绿色棉衣 说话谦卑 没有自信 豆浆两元 手...
    十月云阅读 577评论 12 49