Android 引入FFmpeg 读取RTSP流 解封装获取H264原始数据

2023-05-16

之前 写了Android中怎么引入FFMmpeg的例子 。

本编文章将会写一个简单的demo实现ffmpeg拉去rtsp流并在界面中打印前五个字节

懒得往下细看的可以点击这里下载工程 基于andorid studio 

实际效果下图:

android 用ffmpeg 拉取rtsp流 解出h264数据

看下目录结构:

很简单 应用进去之后有一个主界面MainActivity 主界面有一个按钮点击一下进入一个新的界面会显示解封装的h264数据的包的大小 和前5个字节

MainActivity内容如下:

sdfsdf

package com.qmcy.demux;

import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.qmcy.demux.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'demux' library on application startup.
    static {
        System.loadLibrary("demux");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(GetVersion());

        Button rtsp = (Button)findViewById(R.id.rtsp);
        rtsp.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v)
            {
                Intent intent = new Intent(MainActivity.this,FFDemuxActivity.class);
                startActivity(intent);
            }
        });
    }

    /**
     * A native method that is implemented by the 'demux' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native String GetVersion();

}

FFDemuxActivity代码如下:

package com.qmcy.demux;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

public class FFDemuxActivity extends AppCompatActivity implements FFDemuxJava.EventCallback{

    private static final String TAG = "FFDemuxActivity";
    private static final String[] REQUEST_PERMISSIONS = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
    };
    private static final int PERMISSION_REQUEST_CODE = 1;
    private FFDemuxJava m_demuxer = null;

    private EditText editText;

    private boolean mIsTouch = false;
    private final String mVideoPath = "rtsp://uer:gd123456@192.168.2.123:554/Streaming/Channels/101";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demux);
        editText = findViewById(R.id.output);
        m_demuxer = new FFDemuxJava();
        m_demuxer.addEventCallback(this);
        m_demuxer.init(mVideoPath);
        m_demuxer.Start();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!hasPermissionsGranted(REQUEST_PERMISSIONS)) {
            ActivityCompat.requestPermissions(this, REQUEST_PERMISSIONS, PERMISSION_REQUEST_CODE);
        }
        if(m_demuxer != null)
            m_demuxer.Start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (!hasPermissionsGranted(REQUEST_PERMISSIONS)) {
                Toast.makeText(this, "We need the permission: WRITE_EXTERNAL_STORAGE", Toast.LENGTH_SHORT).show();
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(m_demuxer != null)
        {

        }
    }

    @Override
    protected void onDestroy() {
        m_demuxer.unInit();
        super.onDestroy();
    }



    @Override
    public void onPacketEvent(byte[] data) {
        Log.d(TAG, "onPacketEvent() called with: size = [" + data.length+ "]"+"["+data[0]+" "+data[1]+" "+data[2]+" "+data[3]+" "+data[4]+" "+data[5]+"]");


        String str = "onPacketEvent() called with: size = [" + data.length+ "]"+"["+data[0]+" "+data[1]+" "+data[2]+" "+data[3]+" "+data[4]+" "+data[5]+"]";
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                editText.setText(str);
            }
        });

    }

    @Override
    public void onMessageEvent(final int msgType, final float msgValue) {
        Log.d(TAG, "onPlayerEvent() called with: msgType = [" + msgType + "], msgValue = [" + msgValue + "]");
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                switch (msgType) {

                    case 1:
                        break;
                    default:
                        break;
                }
            }
        });

    }



    protected boolean hasPermissionsGranted(String[] permissions) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(this, permission)
                    != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }


}

FFDemuxJava代码如下:

package com.qmcy.demux;

import android.view.Surface;

public class FFDemuxJava {

    static {
        System.loadLibrary("demux");
    }

    private long m_handle = 0;
    private EventCallback mEventCallback = null;

    public void init(String url) {
        m_handle = native_Init(url);
    }

    public void Start() {
        native_Start(m_handle);
    }

    public void stop() {
        native_Stop(m_handle);
    }

    public void unInit() {
        native_UnInit(m_handle);
    }

    public void addEventCallback(EventCallback callback) {
        mEventCallback = callback;
    }


    private void playerEventCallback(int msgType, float msgValue) {
        if(mEventCallback != null)
            mEventCallback.onMessageEvent(msgType, msgValue);

    }


    private void packetEventCallback(byte[]data) {
        if(mEventCallback != null)
            mEventCallback.onPacketEvent(data);

    }



    private native long native_Init(String url);

    private native void native_Start(long playerHandle);

    private native void native_Stop(long playerHandle);

    private native void native_UnInit(long playerHandle);


    public interface EventCallback {
        void onMessageEvent(int msgType, float msgValue);
        void onPacketEvent(byte []data);
    }

}

然后C++部分的代码 核心的在FFDemux.cpp中 

//
// Created by Administrator on 2022/4/14/014.
//

#include "FFDemux.h"


FFDemux::FFDemux() {

}

FFDemux::~FFDemux() {
    //UnInit();
}

void FFDemux::Start() {
    if(m_Thread == nullptr) {
        StartThread();
    } else {
        std::unique_lock<std::mutex> lock(m_Mutex);
        m_DecoderState = STATE_DEMUXING;
        m_Cond.notify_all();
    }
}


void FFDemux::Stop() {
    LOGCATE("FFDemux::Stop2222");
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_DecoderState = STATE_STOP;
    m_Cond.notify_all();
}


int FFDemux::Init(const char *url) {
    strcpy(m_Url,url);
    return 0;
}

void FFDemux::UnInit() {

    if(m_Thread) {
        Stop();
        m_Thread->join();
        delete m_Thread;
        m_Thread = nullptr;
    }

}



int FFDemux::InitDemux() {
    int result = -1;
    do {
        //1.创建封装格式上下文
        m_AVFormatContext = avformat_alloc_context();

        //2.打开文件
        if(avformat_open_input(&m_AVFormatContext, m_Url, NULL, NULL) != 0)
        {
            LOGCATE("FFDemux::InitDemux avformat_open_input fail.");
            break;
        }

        //3.获取音视频流信息
        if(avformat_find_stream_info(m_AVFormatContext, NULL) < 0) {
            LOGCATE("FFDemux::InitDemux avformat_find_stream_info fail.");
            break;
        }

        //4.获取音视频流索引
        for(int i=0; i < m_AVFormatContext->nb_streams; i++) {
            if(m_AVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
                m_StreamIndex = i;
                break;
            }
        }

        if(m_StreamIndex == -1) {
            LOGCATE("FFDemux::InitFFDecoder Fail to find stream index.");
            break;
        }


        AVDictionary *pAVDictionary = nullptr;
        av_dict_set(&pAVDictionary, "buffer_size", "1024000", 0);
        av_dict_set(&pAVDictionary, "stimeout", "20000000", 0);
        av_dict_set(&pAVDictionary, "max_delay", "30000000", 0);
        av_dict_set(&pAVDictionary, "rtsp_transport", "tcp", 0);


        result = 0;

        m_Packet = av_packet_alloc();

    } while (false);

    if(result != 0 && m_MsgContext && m_MsgCallback)
        m_MsgCallback(m_MsgContext, MSG_DECODER_INIT_ERROR, 0);

    return result;
}

void FFDemux::StartThread() {
//    m_Thread = new thread(DoAVDecoding, this);
    m_Thread = new thread(DoDemux, this);
}



void FFDemux::DemuxLoop() {
    {
        std::unique_lock<std::mutex> lock(m_Mutex);
        m_DecoderState = STATE_DEMUXING;
        lock.unlock();
    }

    for(;;) {

        LOGCATE("111111111111111111111111111   m_DecoderState =%d", m_DecoderState);
        if(m_DecoderState == STATE_STOP) {
            break;
        }

        if(DecodeOnePacket() != 0) {
            //解码结束,暂停解码器
            std::unique_lock<std::mutex> lock(m_Mutex);
            m_DecoderState = STATE_ERROR;
        }
    }
}

int FFDemux::DecodeOnePacket() {

    int result = av_read_frame(m_AVFormatContext, m_Packet);
    while(result == 0) {
        if(m_DecoderState == STATE_STOP)
        {
            LOGCATE("111111111111111111111111111  m_DecoderState is stop");
            break;
        }
        if(m_Packet->stream_index == m_StreamIndex) {
            OnReceivePacket(m_Packet);
            //LOGCATE("111111111111111111111111111   BaseDecoder::DecodeOnePacket_Ex packet size =%d", m_Packet->size);
            //判断一个 packet 是否解码完成

        }
        av_packet_unref(m_Packet);
        result = av_read_frame(m_AVFormatContext, m_Packet);
    }

    __EXIT:
    av_packet_unref(m_Packet);
    return result;
}

void FFDemux::DoDemux(FFDemux *demux) {
    LOGCATE("FFDemux::DoDemux");
    do {
        if(demux->InitDemux() != 0) {
            break;
        }
        demux->DemuxLoop();
    } while (false);

    demux->DeInitDemux();
}



void FFDemux::DeInitDemux() {
    LOGCATE("FFDemux::DeInitDemux");


    if(m_Packet != nullptr) {
        av_packet_free(&m_Packet);
        m_Packet = nullptr;
    }


    if(m_AVFormatContext != nullptr) {
        avformat_close_input(&m_AVFormatContext);
        avformat_free_context(m_AVFormatContext);
        m_AVFormatContext = nullptr;
    }

}

void FFDemux::OnReceivePacket(AVPacket *packet) {

    if(m_MsgContext && m_MsgCallback)
        m_PacketCallback(m_MsgContext, packet->data,packet->size);
}

FFBridge充当cpp和java之间的桥梁 封装了一层 

//
// Created by Administrator on 2022/4/14/014.
//

#include "FFBridge.h"

void FFBridge::Init(JNIEnv *jniEnv, jobject obj, char *url) {
    jniEnv->GetJavaVM(&m_JavaVM);
    m_JavaObj = jniEnv->NewGlobalRef(obj);

    m_demux = new FFDemux();
    m_demux->Init(url);
    m_demux->SetMessageCallback(this, PostMessage);
    m_demux->SetPacketCallback(this, PostPacket);

}

void FFBridge::Start() {
    LOGCATE("FFBridge::Start");
    if(m_demux)
        m_demux->Start();
}

void FFBridge::UnInit() {
    LOGCATE("FFBridge::UnInit");
    if(m_demux) {
        Stop();
        delete m_demux;
        m_demux = nullptr;
    }

    bool isAttach = false;
    GetJNIEnv(&isAttach)->DeleteGlobalRef(m_JavaObj);
    if(isAttach)
        GetJavaVM()->DetachCurrentThread();

}



void FFBridge::Stop() {
    LOGCATE("FFBridge::Stop");
    if(m_demux)
    {
        m_demux->UnInit();
    }
}


JNIEnv *FFBridge::GetJNIEnv(bool *isAttach) {
    JNIEnv *env;
    int status;
    if (nullptr == m_JavaVM) {
        LOGCATE("FFBridge::GetJNIEnv m_JavaVM == nullptr");
        return nullptr;
    }
    *isAttach = false;
    status = m_JavaVM->GetEnv((void **)&env, JNI_VERSION_1_4);
    if (status != JNI_OK) {
        status = m_JavaVM->AttachCurrentThread(&env, nullptr);
        if (status != JNI_OK) {
            LOGCATE("FFBridge::GetJNIEnv failed to attach current thread");
            return nullptr;
        }
        *isAttach = true;
    }
    return env;
}


jobject FFBridge::GetJavaObj() {
    return m_JavaObj;
}

JavaVM *FFBridge::GetJavaVM() {
    return m_JavaVM;
}


void FFBridge::PostMessage(void *context, int msgType, float msgCode) {
    if(context != nullptr)
    {
        FFBridge *player = static_cast<FFBridge *>(context);
        bool isAttach = false;
        JNIEnv *env = player->GetJNIEnv(&isAttach);
       // LOGCATE("FFBridge::PostMessage env=%p", env);
        if(env == nullptr)
            return;
        jobject javaObj = player->GetJavaObj();
        jmethodID mid = env->GetMethodID(env->GetObjectClass(javaObj), JAVA_MESSAGE_EVENT_CALLBACK_API_NAME, "(IF)V");
        env->CallVoidMethod(javaObj, mid, msgType, msgCode);
        if(isAttach)
            player->GetJavaVM()->DetachCurrentThread();

    }
}

void FFBridge::PostPacket(void *context,  uint8_t *buf,int size) {
    if(context != nullptr)
    {
        FFBridge *player = static_cast<FFBridge *>(context);
        bool isAttach = false;
        JNIEnv *env = player->GetJNIEnv(&isAttach);
        //LOGCATE("FFBridge::PostPacket env=%p", env);
        if(env == nullptr)
            return;
        jobject javaObj = player->GetJavaObj();

        jbyteArray  array1 = env->NewByteArray(size);
        env->SetByteArrayRegion(array1,0,size,(jbyte*)buf);


        jmethodID mid = env->GetMethodID(env->GetObjectClass(javaObj), JAVA_PACKET_EVENT_CALLBACK_API_NAME, "([B)V");
        env->CallVoidMethod(javaObj, mid, array1);

        env->DeleteLocalRef(array1);

        if(isAttach)
            player->GetJavaVM()->DetachCurrentThread();

    }
}

然后native 代码都在native-lib.cpp中  

#include <jni.h>
#include <string>

#include "FFBridge.h"

extern "C"
{
#include <libavutil/time.h>
#include <libavcodec/avcodec.h>
#include <libavcodec/packet.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
};

extern "C" JNIEXPORT jstring JNICALL
Java_com_qmcy_demux_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}


extern "C" JNIEXPORT jstring JNICALL
Java_com_qmcy_demux_MainActivity_GetVersion(
        JNIEnv* env,
        jobject /* this */) {
    char strBuffer[1024 * 4] = {0};
    strcat(strBuffer, "libavcodec : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVCODEC_VERSION));
    strcat(strBuffer, "\nlibavformat : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVFORMAT_VERSION));
    strcat(strBuffer, "\nlibavutil : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVUTIL_VERSION));
    strcat(strBuffer, "\nlibavfilter : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVFILTER_VERSION));
    strcat(strBuffer, "\nlibswresample : ");
    strcat(strBuffer, AV_STRINGIFY(LIBSWRESAMPLE_VERSION));
    strcat(strBuffer, "\nlibswscale : ");
    strcat(strBuffer, AV_STRINGIFY(LIBSWSCALE_VERSION));
    strcat(strBuffer, "\navcodec_configure : \n");
    strcat(strBuffer, avcodec_configuration());
    strcat(strBuffer, "\navcodec_license : ");
    strcat(strBuffer, avcodec_license());
    //LOGCATE("GetFFmpegVersion\n%s", strBuffer);
    return env->NewStringUTF(strBuffer);
}


extern "C" JNIEXPORT jlong JNICALL Java_com_qmcy_demux_FFDemuxJava_native_1Init
        (JNIEnv *env, jobject obj, jstring jurl)
{
    const char* url = env->GetStringUTFChars(jurl, nullptr);
    FFBridge *bridge = new FFBridge();
    bridge->Init(env, obj, const_cast<char *>(url));
    env->ReleaseStringUTFChars(jurl, url);
    return reinterpret_cast<jlong>(bridge);
}

extern "C"
JNIEXPORT void JNICALL Java_com_qmcy_demux_FFDemuxJava_native_1Start
        (JNIEnv *env, jobject obj, jlong handle)
{
    if(handle != 0)
    {
        FFBridge *bridge = reinterpret_cast<FFBridge *>(handle);
        bridge->Start();
    }

}

extern "C"
JNIEXPORT void JNICALL Java_com_qmcy_demux_FFDemuxJava_native_1Stop
        (JNIEnv *env, jobject obj, jlong handle)
{
    if(handle != 0)
    {
        FFBridge *bridge = reinterpret_cast<FFBridge *>(handle);
        bridge->Stop();
    }
}


extern "C"
JNIEXPORT void JNICALL Java_com_qmcy_demux_FFDemuxJava_native_1UnInit
        (JNIEnv *env, jobject obj, jlong handle)
{
    if(handle != 0)
    {
        FFBridge *bridge = reinterpret_cast<FFBridge *>(handle);
        bridge->UnInit();
        delete bridge;
    }
}

一直从事的都是 c/c++的开发  对于java的知识 还停留在大学阶段所学的阶段

更别谈android了   很早的几年前 也写过一个简单的手机控制蓝牙的android app 但是那会还是 2015年左右 那会用的还是eclipse 还没有android studio这个ide  。差别还是蛮大的 

参考了csdn的另一位博主 字节流动 的 代码  做个入门阶段的demo 

一些容错处理没处理好 ,毕竟只是个demo。 通过这个demo 了解下 JNI 以及Java C++ 如何交互

以及回调函数怎么处理 等等。

ffmpeg   -rtsp_transport tcp  -i rtsp://uer:gd123456@192.168.2.124:554/Streaming/Channels/101 -vcodec copy -an    -f flv rtmp://192.168.0.209:1935/live/0 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 引入FFmpeg 读取RTSP流 解封装获取H264原始数据 的相关文章

  • ubuntu 下运行程序报错 对‘std::cout’未定义的引用

    在编译c 43 43 程序时运行gcc o fileio fileio cpp报错 xff0c 错误提示为 xff1a tmp ccinWfZ2 o xff1a 在函数 main 中 xff1a fileio cpp text 43 0x2
  • Ubuntu下Python3与Python2相互切换

    python2切换python3 设置Python2及Python3优先级 sudo update span class token operator span alternatives span class token operator
  • 超声波传感器(CH101&ch201) - Ⅱ

    文章目录 1 前言 2 目前官方发布的Horn有以下几种 3 超声波TOF传感器 VS 红外线传感器 4 开发评估套件 1 前言 上一篇简单的引入了CH101 CH201 这两种传感器 这种传感器使用的时候除了需要芯片外 还需要一个声学的
  • 了解 Spark中的master、worker和Driver、Executor

    master和worker是物理节点 xff0c 是在不同环境部署模式下和资源相关的两大内容 Driver和executor是进程 xff0c 是在spark应用中和计算相关的两大内容 1 master和worker节点 master节点常
  • 对Spark中一些基础概念的了解

    1 Driver xff1a 运行应用程序的main函数 xff0c 并创建SparkContext进程 初始化SparkContext是为了准备Spark应用程序的运行环境 xff0c 在Spark中由SparkContext负责与集群进
  • Spark学习总结

    第1章 Spark 概述 1 1 Spark是什么 Spark 是一种基于内存的快速 通用 可扩展的大数据分析计算引擎 主要用于数据计算 xff0c 经常被认为是Hadoop框架的升级版 1 2 Spark 和Hadoop的缘分 组成 Ha
  • RTMP 推送H265的实现(推流端、服务器、播放端)ffmpeg 播放H265

    众所周知的原因原生的RTMP只支持H264 并不支持H265的传输 xff0c 之前的项目基于海思3531DV200平台的多路输入 多路输出 基于FFMpeg 拉RTSP的流 然后通过海思硬件解码然后在编码成较小的分辨率 通过RTMP推流到
  • Visio画UML类图

    用Visio画UML类图 1 首先创建一个类图 接下来我们要做一下准备工作 xff0c 因为我们这里用了PSDK中的POINT类型 xff0c 在种数据类型在visio数据类型中找不到 xff0c 所以我们先得追加这个数据类型 为了便于管理
  • 二维数组的输入、输出、转置

    这里我将在二维数组中的一些基本操作进行一次整理 xff1a 编码思路 xff1a 1 inputTwoArry 输入函数 用于二维数组的初始化 xff08 也就是赋值 xff09 实现 xff1a 给函数中传入要初始化数组的地址 xff0c
  • 输入一句话,找出其中最长的单词,并输出

    理解题意 xff1a 1 先输入一句话 2 在这句话中找到最长的那个单词并输出显示 这个题是我们老师上课的时候给我们留的作业 因为刚好学过了二维数组所以果断采用二维数组来解题 个人觉得 xff0c 这个逻辑思路其实相较一维数组来解会更简单一
  • C语言:将学生信息存储到文件中

    描述 xff1a 从键盘输入两个学生的有关数据 xff0c 然后把它们转存到磁盘文件上去 基础知识点 xff1a 1 定义结构体变量 xff0c 存储复杂一点的变量 xff08 对象 xff09 2 用到了C语言中对文件的处理 3 排序 文
  • Maven的安装、配置以及在Eclipse中安装maven插件

    一 需要准备的东西 xff08 原文链接 xff09 1 首先确保安装了JDK xff0c 并且成功配置了JDK的环境变量 2 已安装Eclipse 3 Maven程序包 二 maven下载与安装 1 前往https maven apach
  • ros多机通信配置

    ros多机通信配置 xff0c 以两台计算机为例 xff0c 主机hostname为master从机hostname为slaver 1 在主机和从机 etc hosts内添加ip和hostname 例如两台计算机ip和hostname分别为
  • RS422接线方法

  • ORB-SLAM2的编译运行以及TUM数据集测试

    近段时间一直在学习高翔博士的 视觉SLAM十四讲 xff0c 学了以后发现自己欠缺的东西实在太多 xff0c 好多都需要深入系统的学习 ORB SLAM2是一套完整的SLAM方案 xff0c 提供了单目 xff0c 双目和RGB D三种接口
  • 【VINS论文翻译】VINS-Mono: A Robust and Versatile Monocular Visual-Inertial State Estimator

    回到目录 写在前面 港科大的VINS Mono作为目前state of the art的开源VIO项目 xff0c 是研究视觉与IMU紧耦合的必读算法 xff0c 网上的论文解读与代码实现也非常丰富 xff08 感谢 xff01 xff09
  • 视觉SLAM十四讲(第二版)章节总结+课后习题分析

    感谢博主nullwh 的分享 xff0c 原文链接 视觉SLAM十四讲 视觉SLAM十四讲 第二版 笔记及课后习题 xff08 第一讲 xff09 视觉SLAM十四讲 第二版 笔记及课后习题 xff08 第二讲 xff09 视觉SLAM十四
  • FFMPEG 编解码失败 non-existing PPS 0 referenced

    最近在尝试用ffmpeg进行编解码 大部分的rtsp拉流正常 编解码正常 但是有的rtsp不能解码 提示如下 xff1a 后来把把packet数据打印出来发现是没有sps pps信息 导致 ffmpeg不能正常解码 程序里面 经过测试 把
  • ROS主从机配置

    目标 xff1a 小车上运行SLAM算法 xff0c 在PC上使用rviz可视化观察 第一步 xff1a 分别在两台机器上使用 hostname 指令查看用户名 ifconfig 指令查看ip地址 wlp3s0是我的pc的无线网卡 xff0
  • Docker入门指南

    https yeasy gitbook io docker practice

随机推荐

  • STL迭代器模版详解

    1 STL iterator迭代器 STL xff08 Standard Template Library xff0c 标准模板库 是惠普实验室开发的一系列软件的统称 它是由Alexander Stepanov Meng Lee和David
  • 4种YOLO目标检测的C++和Python两种版本实现

    本文原创首发于极市平台公众号 xff0c 如需转载请私信作者 2020年 xff0c 新出了几个新版本的YOLO目标检测 xff0c 在微信朋友圈里转发的最多的有YOLOv4 xff0c Yolo Fastest xff0c YOLObil
  • Activity的任务栈Task以及启动模式与Intent的Flag详解

    什么是任务栈 Task 官方文档是这么解释的 任务是指在执行特定作业时与用户交互的一系列 Activity 这些 Activity 按照各自的打开顺序排列在堆栈 xff08 即 返回栈 xff09 中 其实就是以栈的结构 先进后出 将依次打
  • 什么是标记化?令牌?

    什么是标记化 xff1f 标记化就是 xff1a 将敏感数据元素 xff08 例如银行帐号 xff09 替换为非敏感替代项 xff08 称为令牌 xff09 令牌是一个随机数据字符串 xff0c 没有基本或可利用的值或含义 它是一个唯一的标
  • 如何使用c语言解析httppost请求

    头文件 ifndef UPLOAD define UPLOAD include 34 fastcgi fcgiapp h 34 include 34 sysinc h 34 ifdef WIN32 def GRCALL the callin
  • STM32F103ZET6单片机双串口互发程序设计与实现

    STM32库函数开发系列文章目录 第一篇 xff1a STM32F103ZET6单片机双串口互发程序设计与实现 文章目录 STM32库函数开发系列文章目录前言一 STM32F103ZET6单片机双串口互发程序设计与实现是什么 xff1f 二
  • STL的一些常见应用场景

    set 集合 去除重复元素并从小到大排序 平衡二叉树 xff08 红黑树 xff09 维护 span class token comment 华为机试 gt HJ3 span span class token macro property
  • Pixhawk原生固件Linux环境下编译

    Pixhawk原生固件在Linux下编译的资料网上很多 xff0c 官网 http dev px4 io starting installing linux html 也有其具体流程 xff0c 本文只是针对自己从安装ubuntu14 04
  • GNGGA 解析北斗数据获得经纬度 以及数据NMEA数据转换

    char GPS1 61 34 GNGGA 121252 000 3937 3032 N 11611 6046 E 1 05 2 0 45 9 M 5 7 M 0000 77 34 int Parse GPS char data char
  • C++ math.h函数

    include int abs int num double fabs double arg long labs long num 函数返回num的绝对值 include double acos double arg 函数返回arg的反余弦
  • 动态ip原理

    所谓动态是指每次上网时 xff0c 运营商会随机从池子中分配一个IP地址 xff0c 动态ip池子因不同服务机构质量有所不同 xff0c 透明一般是在免费代理中出现 xff0c 而不同透明度还是有相应区分 代理IP的匿名度 xff1a 匿名
  • 自建隧道代理

    隧道代理可自动变更 xff0c 免去频繁更换代理的麻烦 xff0c 仅需一次性配置一个代理IP xff0c 其它变IP工作由隧道自动完成 假设你从免费代理手上拿到一些池子 xff0c 当然你也可以用爬虫程序自己爬找出后测试筛选可用的 xff
  • socks5代理怎么用?如何使用?

    SOCKS5代理不会重写数据包的标头 xff0c 并结合了TCP和UDP协议 Sock5代理服务器是把你的网络数据请求通过一条连接你和代理服务器之间的通道 xff0c 由服务器转发到目的地 Proxifier是一款功能非常强大的socks5
  • Python代理ip代码示例

    隧道代理和其他代理ip也有共同点优势比路由器更容易配置 xff0c 可以在工作过程中生成各种记录 xff0c 工作在应用层 xff0c 可以对各种数据进行检查 xff0c 按照一定的准则 xff0c 生成各种日志 记录 除此之外 xff0c
  • python 爬虫SSL错误是怎么回事?

    今天摸鱼 xff08 划掉 xff09 看道一个问题蛮有意思的 xff0c 想来展开说说 xff1a 别急 xff0c 解决办法是有的 1 这个错误很可能是因为你正在尝试读取一个 JSON 格式的响应 xff0c 但是实际返回的却是 HTM
  • python写的爬虫,抓取百度的搜索结果,被屏蔽了怎么办?

    某乎上有个热门话题 xff0c 引起了很大的讨论 这个问题通常是由于频繁的请求导致百度的反爬虫机制触发了验证码的保护机制 解决办法无非是那几套流程走一遍 1 增加请求的时间间隔 通过在每个请求之间增加一些时间间隔 xff0c 可以降低请求频
  • HTTP代理挑选最强攻略

    最近上班合理上网的时候 xff0c 在某乎上刷到一个话题 xff0c 本来这个话题我也经常刷到没打算看 xff0c 本着看新动态的心思 xff0c 点进来一看 xff0c 好家伙 xff0c 这话题底下除了各大HTTP代理服务商 xff0c
  • 电设飞控从零学起(一) 基础篇 无人机硬件与结构设计简介

    1 常见无人机的分类 xff08 1 xff09 固定翼 xff1a 续航时间长 xff0c 载荷最大 xff0c 但必须助跑 滑行 xff08 2 xff09 直升机 xff1a 可垂直起降 xff0c 但机械结构复杂 维护成本高 xff
  • ROS编程 csv文件读取/输出 与 YAML文件生成

    前言 代码是抄的 感想是真的 cpp的文件操作对比起python来说是比较繁复的 而每次学习cpp的时候都会去刻意留文件操作的教程 其实直接做一次实验就可以理解了 下面的代码是抄回来 xff0c 分别是做手眼标定与力传感器标定过程中需要将采
  • Android 引入FFmpeg 读取RTSP流 解封装获取H264原始数据

    之前 写了Android中怎么引入FFMmpeg的例子 本编文章将会写一个简单的demo实现ffmpeg拉去rtsp流并在界面中打印前五个字节 懒得往下细看的可以点击这里下载工程 基于andorid studio 实际效果下图 xff1a