【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

这篇具有很好参考价值的文章主要介绍了【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.硬件改造

2.软件改造

3.下一步计划


背景是23年4月入了随身wifi的坑后,发现除了硬件上的改造,软件的可玩性也很大,网上可以找到不少打印机,直播推流,甚至家庭智能硬件的改造教程。笔者是因为改造遥控小车,接触到了随身wifi。因为早年市场上的商用的智能车大多运行linux系统,上面叠加一个摄像头,以mjpg的方式提供视频流。而现在无论是车还是手机,硬件能力都有大幅度提升,h264/h265已经成为主流。随身wifi的硬件是高通410,还没有硬件编码能力,软件编码找了一圈也没有人研究,在此背景下,产生了动手的想法。

1.硬件改造

要让随身wifi接摄像头,必要的硬件改造还是需要的,酷安上可以买到随身wifi的扩展板,也不贵。我追求硬件的体积小,所以就自己焊接了,随身wifi的usb的四个触点接usb摄像头的四个触点,额外引出两根电源线接5v电源。实际就是2公1母的usb延长线,马云家店里应该能买到。注意,焊接前先把随身wifi的系统烧录好,wifi可用,不然焊接了没usb口,连不上电脑,后面的软件改造就执行不下去了。

2.软件改造

第一步,把usb设置成host模式,不然识别不了usb摄像头,成功后/dev/video0设备就出现了,笔者的openwrt是/dev/video0,debian是/dev/video2。另外以下脚本是根据usb口是否接电源判定是否host模式,推荐使用,万一把无线搞坏了,usb口还能救砖。不计较时间成本,有备份恢复大法的可以忽略。

grep 0 /sys/kernel/debug/usb/ci_hdrc.0/device | grep speed
if [ $? -eq 0 ]
then
echo host > /sys/kernel/debug/usb/ci_hdrc.0/role
fi

第二步,debian安装ffmpeg

这个就不多说了,apt安装即可,很方便。但是,cpu占用较高,唯一的好处是插件很全,安装使用方便。

第三步,openwrt编译ffmpeg

为什么又折腾openwrt,笔者是因为debian在网络管理上功能缺失,对openwrt有依赖,所以不得不切换到openwrt。注意,以下教程在openwrt21.2上测试通过,更老的版本没试,主要是ffmpeg对cpu性能要求太高,太老的硬件没有意义。

openwrt的opkg install ffmpeg命令可以安装一个full版本的ffmpeg,但实际使用过程发现没有debian上支持的插件多,基本的x264,preset命令都不支持,所以产生了自己编译的想法,在我写这篇文章的时候,随身wifi的openwrt固件版本都是21.02,苏苏亮亮,水遍编译的固件都是基于github上HandsomeMod魔改而来,所以下载HandsomeMod编译即可

https://github.com/HandsomeMod

首先在menuconfig中,在multimeia下选择ffmpeg,,然后在library下选择libffmpeg-full和libx264.请按以下步骤操作:

图1:选择[Compile with support for patented functionality]

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

图2: 选择 [libffmpeg-full]和[]

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

 【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

图3: 选择[ffmpeg] 

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

然后修改Makefile:

文件头部新增如下两行:

CONFIG_PACKAGE_libx264:=1
CONFIG_FFMPEG_CUSTOM_NONFREE:=1

改完是这个样子:

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

然后是修改full中编译的插件:

vim package/feeds/packages/ffmpeg/Makefile

找到 ifeq ($(BUILD_VARIANT),full)


注释掉disable
        ##      $(if $(CONFIG_BUILD_PATENTED),, \
        ##              $(call FFMPEG_DISABLE,decoder,$(FFMPEG_PATENTED_DECODERS)) \
        ##              $(call FFMPEG_DISABLE,encoder,$(FFMPEG_PATENTED_ENCODERS)) \
        ##              $(call FFMPEG_DISABLE,muxer,$(FFMPEG_PATENTED_MUXERS)) \
        ##              $(call FFMPEG_DISABLE,demuxer,$(FFMPEG_PATENTED_DEMUXERS)) \
        ##              $(call FFMPEG_DISABLE,parser,$(FFMPEG_PATENTED_PARSERS))) \


新增enable
        $(call FFMPEG_ENABLE,encoder,$(FFMPEG_CUSTOM_ENCODERS),CONFIG_FFMPEG_CUSTOM_ENCODER) \
        $(call FFMPEG_ENABLE,decoder,$(FFMPEG_CUSTOM_DECODERS),CONFIG_FFMPEG_CUSTOM_DECODER) \
        $(call FFMPEG_ENABLE,muxer,$(FFMPEG_CUSTOM_MUXERS),CONFIG_FFMPEG_CUSTOM_MUXER) \
        $(call FFMPEG_ENABLE,demuxer,$(FFMPEG_CUSTOM_DEMUXERS),CONFIG_FFMPEG_CUSTOM_DEMUXER) \
        $(call FFMPEG_ENABLE,parser,$(FFMPEG_CUSTOM_PARSERS),CONFIG_FFMPEG_CUSTOM_PARSER) \
        $(call FFMPEG_ENABLE,protocol,$(FFMPEG_CUSTOM_PROTOCOLS),CONFIG_FFMPEG_CUSTOM_PROTOCOL) \
        

改完是这个样子

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

 然后就是编译了,很快,10分钟完事。

编译成功,后可以刷整个system镜像,也可以把编译出来的ipk拷贝到openwrt中手动安装,因为ffmpeg是纯软件实现,对内核和其他组件依赖较小,所以我采用的是后者。

新编译出来如下ipk文件,拷贝到openwrt中安装即可

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

第四步,运行ffmpeg

openwrt上编译后的ffmpeg与debian上安装的ffmpeg,插件一致,命令就可以保持相同,笔者的目的是把usb摄像头中的视频流取出来,h264编码后,发送到手机,ffmpeg命令可以这么写:

ffmpeg -y -f v4l2 -i /dev/video0 -vcodec libx264 -pix_fmt yuv420p -maxrate 1M -bufsize 4M -f h264 -

最后一个"-"表示输出到pipe中,可以再用其他命令想办法把视频流发送到手机侧

第五步,安卓侧播放流媒体

因为服务端用的ffmpeg,所以很多同学就会想当然认为手机侧播放也依赖ffmpeg,而且网上搜安卓+ffmpeg,出来的大多是怎么编译ffmpeg的so,怎么写jni,怎么在android写java代码调用c代码库,甚至还有github上现成编译好或者叫二次封装过的安卓版ffmpeg库可以用。笔者decompile了不少支持h264流媒体播放的apk也都是这么干的。

上面的这些手段,笔者都尝试过,坑也踩过。现在,都不需要了,因为近几年绝大部分的安卓手机都支持硬件解码了,在安卓侧,直接可以调用安卓自带的MediaCodec接口使用硬解h264流媒体了,代码量还很少,运行效率高。

主要的类:H264SurfaceView,github>>>>>

package com.xxx.h264player;

import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import java.nio.ByteBuffer;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


public class H264SurfaceView extends SurfaceView implements SurfaceHolder.Callback  {
    static int mVideoHeight = 480;
    static int mVideoWidth = 640;
    public float ZOOM[] = {
        100F, 125F, 150F, 175F, 200F
    };
    public static int[] Video_WandH = new int[] { 640, 480 };
    Bitmap bitmap;
    float bx;
    float bx1;
    float by;
    float by1;
    long donw_time;
    public boolean isFirstChange;
    public int streamsize;
    private int targetZoom;
    int mCodecState = -1;
    Surface mSurface;
    MediaCodec mCodec;
    SurfaceHolder mSurfaceHolder;
    private int mFrameIndex = 0;

    public H264SurfaceView(Context context)
    {
        super(context);
        streamsize = 0;
        targetZoom = 0;
        bx1 = 0.0F;
        by1 = 0.0F;
        isFirstChange = true;
        initial();
    }

    public void initMediaCodec() {
        if (mCodecState > 0) return;

        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", Video_WandH[0], Video_WandH[1]);

        /*mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1);
        mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 1);
        mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);*/

        try {
            mCodec = MediaCodec.createDecoderByType("video/avc");
            if (mSurface != null && mSurface.isValid()) {
                mCodec.configure(mediaFormat, mSurface, null, 0);
                mCodec.start();
                mCodecState = 1;
            }
        } catch (Exception e) {
            Log.e("CameraView", " MediaCodec == " + e.getMessage());
            return;
        }
    }

    public H264SurfaceView(Context context, AttributeSet attributeset)
    {
        super(context, attributeset);
        streamsize = 0;
        targetZoom = 0;
        bx1 = 0.0F;
        by1 = 0.0F;
        isFirstChange = true;
        initial();
    }

    public final int getTargetZoom()
    {
        return targetZoom;
    }

    public float getTargetZoomValue()
    {
        return ZOOM[targetZoom];
    }

    public void initial()
    {
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        initMediaCodec();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }
 


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mSurface = holder.getSurface();
        initMediaCodec();
    }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mSurface != null) {
            mSurface.release();
        }
        mSurface = null;
    }

    public final void setTargetZoom(int i)
    {
        targetZoom = i;
    }

    public void takePicture()
    {
        //AppCameraSurfaceFunction.getAppCameraSurfaceFunctionInstance().CameraTakePicture();
    }

    public int zoomIn()
        throws InterruptedException
    {
        if(targetZoom >= 0 && targetZoom < 4)
        {
            //AppDecodeH264.GlZoomIn();
            targetZoom = targetZoom + 1;
        }
        return targetZoom;
    }

    public void zoomInit()
    {
        //AppDecodeH264.GlZoomInit();
        targetZoom = 0;
    }

    public int zoomOut()throws InterruptedException{
        if(targetZoom > 0 && targetZoom <= 4)
        {
            //AppDecodeH264.GlZoomOut();
            targetZoom = targetZoom - 1;
        }
        return targetZoom;
    }

    private byte[] Bitmap2Bytes() {
        Bitmap bitmap;
        byte abyte0[];
        int i=0;
        bitmap = Bitmap.createBitmap(Video_WandH[0], Video_WandH[1], android.graphics.Bitmap.Config.ARGB_8888);
        abyte0 = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
        int height = bitmap.getHeight();
        int width = bitmap.getWidth();
        while (i < height) {
            int j = 0;
            while (j < width) {
                abyte0[i * j] = (byte)0;
                j++;
            }
            i++;
        }
        return abyte0;
    }
    
    public void decodeOneFrame(byte[] data, int length) {
        if (mSurface != null && mSurface.isValid()) {
            if (mCodec != null) {
                try {

                    int inputBufferIndex = mCodec.dequeueInputBuffer(0);
                    if (inputBufferIndex >= 0) {
                        ByteBuffer inputBuffer = mCodec.getInputBuffers()[inputBufferIndex];
                        long timestamp = mFrameIndex++ * 1000000 / 30;
                        inputBuffer.clear();
                        inputBuffer.put(data, 0, length);
                        mCodec.queueInputBuffer(inputBufferIndex, 0, length, timestamp, 0);
                    }
                    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                    int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
                    while (outputBufferIndex >= 0) {
                        mCodec.releaseOutputBuffer(outputBufferIndex, true);
                        outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
                    }
                } catch (Throwable t) {
                    //Log.e(TAG, "offerDecoder233 == " + t.toString() + t.getMessage());

                    release();
                }

            } 
        }
    }
    public void release() {
        if (mCodec != null) {
            mCodec.release();
            mCodec = null;
        }
    }

    public void stop() {
        if (mCodec != null) {
            mCodec.stop();
            mCodecState = 0;
        }
    }
    
    public void start() {
        if (mCodec != null) {
            mCodec.start();
            mCodecState = 1;
        }
    }
}

3.下一步计划

做了这么多,很多人关心视频质量如何,实际笔者测试过,网络条件正常的时候,分辨率720p以下,视频流畅度上h264和mjpg一样的,延迟h264高些,网络不好的时候,h264流畅度上略好。下一步,笔者计划把抽屉里的几个摄像头都翻出来,测试下1080p,720p,480p这些不同分辨率,不同码率下,视频的清晰度到底如何,给不同应用场景下摄像头的选择提供实际的数据。文章来源地址https://www.toymoban.com/news/detail-501845.html

到了这里,关于【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FFMPEG使用DrawText滤镜添加字幕,包含ndk编译freetype

            ffmpeg使用drawtext滤镜需要在编译的时候使能drawtext,要想成功使能必须要先集成编译freetype库,并通知到ffmpeg(交叉编译没有安装到系统库路径)。         也有看到有的文章说需要集成fribidi,笔者也交叉编译了,但是最终没有用到,可能是ffmpeg版本的原因。 freety

    2024年01月17日
    浏览(73)
  • 瑞星随身wifi不能上网怎么办?瑞星随身wifi无法上网问题解决方法

    瑞星随身wifi不能上网怎么办?我们可能会遇到瑞星随身wifi连接成功但手机无法上网这样类似的故障,这是无线路由使用过程中最常见的问题,遇到瑞星随身wifi无法上网故障时怎么办呢?今天小编就为大家带来瑞星随身wifi连接成功但手机无法上网原因及解决方法,有兴趣的朋友

    2024年02月06日
    浏览(63)
  • 小米随身Wifi怎么用 小米随身Wifi安装使用教程图解

    小米随身Wifi是一款功能类似360随身Wifi的USB迷你无线路由器,让无线网络共享变得非常简单!将小米随身WiFi连接任何可以上网的台式电脑或者笔记本,就可以轻松让我们的智能手机、Pad平板等移动设无线备免费Wifi上网。尽管小米随身Wifi使用简单,但初次使用,我们还是需要

    2024年02月06日
    浏览(57)
  • 小米随身wifi为什么创建不了?小米wifi创建失败解决方法

    小米随身wifi为什么创建不了?现在很多朋友在使用小米随身wifi的过程中遇到了创建失败的情况,那么怎么办呢?下面小编就为大家介绍小米wifi创建失败的解决方法,一起来看看吧! 解决小米wifi创建失败方法步骤: 第一步、鼠标移至“我的电脑”右键打开“管理”。 第二步

    2024年02月07日
    浏览(46)
  • 瑞星随身Wifi怎么用 瑞星安全随身WiFi安装使用教程图文详解

    瑞星安全随身wifi是瑞星公司推出的一款具有安全方面特性的随身WiF产品,与360随身WiFi、小米随身WiFi以及百度WiFi产品相比,最大的特点是加入了无线安全方面的技术,从而使无线上网更安全。下面小编就带大家了解下瑞星安全随身WiFi的使用方法和特色介绍。 瑞星安全随身

    2024年02月06日
    浏览(48)
  • 瑞星安全随身WiFi的常见问题解决方法汇总介绍

    瑞星安全随身WiFi的上市,吸引了不少网友的关注,yii666小编也收到了不少关于瑞星安全随身WiFi的一些常见问题汇总了一下,并一一作了解决。大部w分回答来自瑞星官方,敬请参考。希望对朋友们有所帮助! 问:瑞星为什么要出安全随身WiFi? 答:瑞星一直专注安全,现在Wi

    2024年02月06日
    浏览(51)
  • 随身WiFi安装青龙面板通用依赖安装及部分报错解决方法

    使用方法:到 青龙面板--依赖管理--新建依赖 依赖类型选择对应名称 一键复制下面的依赖,粘贴到 名称 可填写框框 记得选自动拆分 NodeJs 依赖库 当添加所有的依赖库均出现安装失败,且提示源问题,可尝试使用 ssh 工具进入青龙面板容器,执行下方代码。 Python3 依赖库 Li

    2024年02月20日
    浏览(50)
  • NDK编译ffmpeg包含硬件加速vulkan和mediacodec

    NDK编译ffmpeg包含硬件加速vulkan和mediacodec flyfish ffmpeg:ffmpeg-6.0 NDK:android-ndk-r25c 硬件加速:vulkan 和 mediacodec target CPU:armv8-a host:Ubuntu 22.04 因为这里要编译硬件加速版本的ffmpeg-6.0,所以需要把vulkan中include下的两个文件夹 vk_video 和 vulkan 拷贝到 android-ndk-r25c/toolchains/llvm/prebuil

    2024年02月12日
    浏览(35)
  • openwrt (一):特殊的WiFi驱动移植方法

            openwrt的去驱动移植灵活多样,总体来说只要掌握了官方提供的操作方法即可可简单上手,但是也有一些稍微比较特殊的操作。比如说backport模块。         由于需要兼容很多不同版本的Linux驱动,很多时候需要用到backport。因此,如果已有的项目WiFi驱动是在b

    2024年02月07日
    浏览(73)
  • win10系统无法创建使用小米随身WiFi怎么办?

    刚刚更新win10系统(9926),准备用小米随身WiFi开热点。驱动不上啊、坑!!于是捣鼓半天终于弄好了,特地给大家分享经验。系统信息:win10消费者预览版9926 第一步:安装小米随身WiFi安装完之后多半是不能成功创建的!(如果不小心创建了,那么恭喜你!) 第二步:找到驱

    2024年02月08日
    浏览(139)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包