交叉编译源码的方式移植ffmpeg-rockchip

获取ffmpeg源码

git submodule add -f https://github.com/FFmpeg/FFmpeg.git thirdparty/FFmpeg

瑞芯微ffmpeg-rk

git clone https://github.com/jjm2473/ffmpeg-rk/tree/enc#

 参考的一位博主的说法

使用 ffmpeg-rochip 的好处

传统的使用硬件编解码的开发思路是:使用 ffmpeg 获取视频流,然后用 MPP 库进行硬件编解码,最后再传给 ffmpeg 进行复用,生成容器文件或推流。这样做的缺点是整个开发成本较高,需要学习 ffmpeg,还要学习 MPP库。

而现在有了 ffmpeg-rochip 之后,我们可以省略去学习使用 MPP 库的步骤,因为这个库已经帮我们封装好了 MPP 的功能,我们只需要像之前那样使用 ffmpeg 即可,只需在使用编解码器时换成 xxx_rkmpp,比如 h264_rkmpp。这样做的好处就是大大降低我们的开发学习成本。

ffmpeg-rockchip源码编译流程

首先git clone,设置好交叉编译环境写PKG环境变量,这一点很重要

export PKG_CONFIG_SYSROOT_DIR=/home/zhangyu/RK3588/rk3588-buildroot-2021.11-sdk-v1.0/buildroot/output/rockchip_rk3588/host/aarch64-buildroot-linux-gnu/sysroot
export RKMPP_PC_PATH=/home/zhangyu/RK3588/rk3588-buildroot-2021.11-sdk-v1.0/buildroot/output/rockchip_rk3588/host/aarch64-buildroot-linux-gnu/sysroot/usr/lib/pkgconfig
export PKG_CONFIG_LIBDIR=${RKMPP_PC_PATH}:${PKG_CONFIG_SYSROOT_DIR}/usr/lib/pkgconfig:${PKG_CONFIG_SYSROOT_DIR}/usr/share/pkgconfigexport PKG_CONFIG_LIBDIR=${RKMPP_PC_PATH}:${PKG_CONFIG_SYSROOT_DIR}/usr/lib/:${PKG_CONFIG_SYSROOT_DIR}/usr/share/pkgconfig
export LD_LIBRARY_PATH="/home/zhangyu/RK3588/rk3588-buildroot-2021.11-sdk-v1.0/buildroot/output/rockchip_rk3588/host/lib:$LD_LIBRARY_PATH"

文件路径根据自己的buildroot文件更改,目的是让pkg-config能找到对应的包,

pkg-config libdrm -exists
pkg-config rk_mpp -exists    

echo $

输出为0,则说明能找到

进入ffmpeg-rockchip根目录下,

./configure --enable-version3 \--enable-nonfree \--enable-gpl \--sysroot=$HOME/RK3588/rk3588-buildroot-2021.11-sdk-v1.0/buildroot/output/rockchip_rk3588/host/aarch64-buildroot-linux-gnu/sysroot \--prefix=/home/zhangyu/ffmpeg-rk-test/build\--target-os=linux \--arch=aarch64 \--cc=aarch64-buildroot-linux-gnu-gcc \--enable-cross-compile \--disable-x86asm \--enable-shared \--disable-static\--enable-libdrm \--enable-rkmpp\--enable-rkrga\--disable-doc\--disable-debug\--disable-hardcoded-tables\--disable-mipsdsp\--disable-mipsfpu\--disable-hardcoded-tables \--disable-stripping\--extra-cflags="-fno-builtin-lrintf -fno-builtin-lrint" \--extra-ldflags="-lm"\--enable-protocols\--enable-network
make
make install

根据情况做出更改

ffmpeg rtsp流推流验证,

#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
#include <thread>
#include <chrono>extern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavutil/imgutils.h>#include <libavutil/time.h>
}struct Frame {
void* data;
size_t size;
int width;
int height;
int pitch;
std::string cameraId;
std::string cameraName;
uint64_t timestamp;
};void log_error(int ret, const std::string& msg) {char buf[256];av_strerror(ret, buf, sizeof(buf));std::cerr << msg << " Error: " << buf << std::endl;
}int main() {av_log_set_level(AV_LOG_ERROR); // 只显示错误信息,避免日志过多avformat_network_init();// 初始化白帧和黑帧(Y分量)uint8_t buffW[1920 * 1080];uint8_t buffB[1920 * 1080];memset(buffW, 255, sizeof(buffW));memset(buffB, 0, sizeof(buffB));Frame frameWhite = { .data = buffW, .size = 1920 * 1080, .width = 1920, .height = 1080, .pitch = 1920 };Frame frameBlack = { .data = buffB, .size = 1920 * 1080, .width = 1920, .height = 1080, .pitch = 1920 };Frame* doubleBuffer[2] = { &frameWhite, &frameBlack };const char* outUrl = "rtsp://10.168.1.103:8554/live/stream1";// 查找硬件编码器(Rockchip)const AVCodec* codec = avcodec_find_encoder_by_name("h264_rkmpp");if (!codec) {std::cerr << "Encoder h264_rkmpp not found\n";return -1;}AVCodecContext* codecCtx = avcodec_alloc_context3(codec);codecCtx->width = 1920;codecCtx->height = 1080;codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;codecCtx->time_base = AVRational{1, 25}; // 设置帧率为25fpscodecCtx->framerate = AVRational{25, 1};if (avcodec_open2(codecCtx, codec, nullptr) < 0) {std::cerr << "Failed to open codec\n";return -1;}// 创建输出格式上下文(RTSP)AVFormatContext* fmtCtx = nullptr;avformat_alloc_output_context2(&fmtCtx, nullptr, "rtsp", outUrl);if (!fmtCtx) {std::cerr << "Could not allocate output context\n";return -1;}// 添加视频流并设置其参数AVStream* videoStream = avformat_new_stream(fmtCtx, codec);videoStream->time_base = codecCtx->time_base;avcodec_parameters_from_context(videoStream->codecpar, codecCtx);// 设置RTSP推流选项AVDictionary* opts = nullptr;av_dict_set(&opts, "rtsp_transport", "tcp", 0); // 使用TCP传输av_dict_set(&opts, "stimeout", "5000000", 0);   // 设置超时5秒// ⚠️ 不要调用 avio_open2 —— RTSP 使用的是 URL 打开方式,直接调用 avformat_write_header 即可。// 正确方式:建立连接并写入头部信息if (avformat_write_header(fmtCtx, &opts) < 0) {std::cerr << "Failed to write header to output\n";return -1;}// 创建并初始化帧AVFrame* frame = av_frame_alloc();frame->format = codecCtx->pix_fmt;frame->width = codecCtx->width;frame->height = codecCtx->height;av_frame_get_buffer(frame, 32);// 创建编码后的数据包AVPacket* pkt = av_packet_alloc();int64_t pts = 0;int index = 0;while (true) {Frame* src = doubleBuffer[index];index = !index;// 将灰度图像写入Y分量memcpy(frame->data[0], src->data, 1920 * 1080);// UV分量设置为中性值(灰色)memset(frame->data[1], 128, 1920 * 1080 / 4);memset(frame->data[2], 128, 1920 * 1080 / 4);frame->pts = pts++;int ret = avcodec_send_frame(codecCtx, frame);if (ret < 0) {log_error(ret, "send_frame");continue;}while (ret >= 0) {ret = avcodec_receive_packet(codecCtx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;if (ret < 0) {log_error(ret, "receive_packet");break;}pkt->stream_index = videoStream->index;pkt->pts = av_rescale_q(pkt->pts, codecCtx->time_base, videoStream->time_base);pkt->dts = av_rescale_q(pkt->dts, codecCtx->time_base, videoStream->time_base);pkt->duration = av_rescale_q(pkt->duration, codecCtx->time_base, videoStream->time_base);av_interleaved_write_frame(fmtCtx, pkt);av_packet_unref(pkt);}std::this_thread::sleep_for(std::chrono::milliseconds(40)); // 控制帧率25fps}// 清理资源av_write_trailer(fmtCtx);avcodec_free_context(&codecCtx);avformat_free_context(fmtCtx);av_frame_free(&frame);av_packet_free(&pkt);return 0;
}

FFmpeg初始化验证

#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}int main() {// // 初始化 FFmpeg 网络模块(可选)// avformat_network_init();// 打印 FFmpeg 版本信息std::cout << "=== FFmpeg 库测试 ===" << std::endl;std::cout << "avcodec 版本: " << avcodec_version() << std::endl;std::cout << "avformat 版本: " << avformat_version() << std::endl;std::cout << "avutil 版本: " << avutil_version() << std::endl;return 0;
}

查找编码器

ffmpeg -encoders | grep h264

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

9.0 C# 调用solidworks介绍1

一、C# 与 SolidWorks 联合开发概述 SolidWorks 提供了完整的 API(应用程序接口),允许开发者使用 C# 等编程语言进行二次开发,实现自动化设计、定制功能等。 主要技术要点包括: 1. API 结构:SolidWorks API 是基于 COM 的接口,包含数百个对象和数千个方法…

AD 多层线路及装配图PDF的输出

装配图的输出&#xff1a; 1.点开‘智能PDF’ 2. 设置显示顶层&#xff1a; 设置显示底层&#xff1a; 多层线路的输出 同样使用‘智能PDF’

SpringBoot + Shiro + JWT 实现认证与授权完整方案实现

SpringBoot Shiro JWT 实现认证与授权完整方案 下面博主将详细介绍如何使用 SpringBoot 整合 Shiro 和 JWT 实现安全的认证授权系统&#xff0c;包含核心代码实现和最佳实践。 一、技术栈组成 技术组件- 作用版本要求SpringBoot基础框架2.7.xApache Shiro认证和授权核心1.…

PCIe数据采集系统详解

PCIe数据采集系统详解 在上篇文章中&#xff0c;废了老大劲儿我们写出了PCIe数据采集系统&#xff1b;其中各个模块各司其职&#xff0c;相互配合。完成了从数据采集到高速存储到DDR3的全过程。今天我们呢就来详细讲解他们之间的关系&#xff1f;以及各个模块的关键点&#xff…

2025云智算技术白皮书

1. 云智算的演进背景 传统云计算面临三大挑战&#xff1a; 算力需求激增&#xff1a;AI大模型训练需十万卡级GPU集群&#xff0c;资源调度能力不足。网络性能瓶颈&#xff1a;TB级参数同步对低时延、高吞吐要求远超传统网络架构。服务形态单一&#xff1a;IaaS/PaaS无法覆盖A…

C语言编程中的时间处理

最简单的time 在C语言编程中&#xff0c;处理时间最简单的函数就是time了。它的原型为&#xff1a; #include <time.h> time_t time(time_t *_Nullable tloc);返回自从EPOCH&#xff0c;即1970年1月1日的零点零时零分&#xff0c;到当前的秒数。 输入参数可以是NULL。…

适应性神经树:当深度学习遇上决策树的“生长法则”

1st author: Ryutaro Tanno video: Video from London ML meetup paper: Adaptive Neural Trees ICML 2019 code: rtanno21609/AdaptiveNeuralTrees: Adaptive Neural Trees 背景 在机器学习领域&#xff0c;神经网络&#xff08;NNs&#xff09;凭借其强大的表示学习能力&…

InitVerse节点部署教程

项目介绍: InitVerse 是一个为新兴企业量身定制的自动化 Web3 SaaS 平台,只需单击几下即可快速开发和部署 DApp。在 INIChain 和 INICloud 的支持下,InitVerse 可以根据需求动态调整计算资源,实现高效的任务处理,同时提供更高的安全性、可用性和可扩展性。 系统要求: C…

阿里开源通义万相 Wan2.1-VACE,开启视频创作新时代

0.前言 阿里巴巴于2025年5月14日正式开源了其最新的AI视频生成与编辑模型——通义万相Wan2.1-VACE。这一模型是业界功能最全面的视频生成与编辑工具&#xff0c;能够同时支持多种视频生成和编辑任务&#xff0c;包括文生视频、图像参考视频生成、视频重绘、局部编辑、背景延展…

解决“VMware另一个程序已锁定文件的一部分,进程无法访问“

问题描述 打开VMware里的虚拟机时&#xff0c;弹出"另一个程序已锁定文件的一部分&#xff0c;进程无法访问"如图所示&#xff1a; 这是VM虚拟机的保护机制。虚拟机运行时&#xff0c;为防止数据被篡改&#xff0c;会将所运行的文件保护起来。当虚拟机崩溃或者强制…

基于大数据的租房信息可视化系统的设计与实现【源码+文档+部署】

课题名称 基于大数据的租房信息可视化系统的设计与实现 学 院 专 业 计算机科学与技术 学生姓名 指导教师 一、课题来源及意义 租房市场一直是社会关注的热点问题。随着城市化进程的加速&#xff0c;大量人口涌入城市&#xff0c;导致租房需求激增。传统的租…

Vue3封装公共图片组件

对图片加载做的处理: 图片加载状态响应式管理图片访问错误的处理机制图片懒加载可通过slot支持自定义加载动画其他监听事件的处理及向上传递 …<!-- components/CustomImage.vue --> <template><div class="custom-image-wrapper"><!-- 主图 -…

车道线检测----CLRKDNet

今天的最后一篇 车道线检测系列结束 CLRKDNet&#xff1a;通过知识蒸馏加速车道检测 摘要&#xff1a;道路车道是智能车辆视觉感知系统的重要组成部分&#xff0c;在安全导航中发挥着关键作用。在车道检测任务中&#xff0c;平衡精度与实时性能至关重要&#xff0c;但现有方法…

Python-感知机以及实现感知机

感知机定义 如果有一个算法&#xff0c;具有1个或者多个入参&#xff0c;但是返回值要么是0&#xff0c;要么是1&#xff0c;那么这个算法就叫做感知机&#xff0c;也就是说&#xff0c;感知机是个算法 感知机有什么用 感知机是用来表示可能性的大小的&#xff0c;我们可以认…

STM32 ADC+DMA+TIM触发采样实战:避坑指南与源码解析

知识点1【TRGO的介绍】 1、TRGO的概述 TRGO&#xff1a;Trigger Output&#xff08;触发输出&#xff09;&#xff0c;是定时器的一种功能。 它可以作为外设的启动信号&#xff0c;比如ADC转换&#xff0c;DAC输出&#xff0c;DMA请求等。 对于ADC来说&#xff0c;可以通过…

Qwen3技术报告解读

https://github.com/QwenLM/Qwen3/blob/main/Qwen3_Technical_Report.pdf 节前放模型&#xff0c;大晚上的发技术报告。通义&#xff0c;真有你的~ 文章目录 预训练后训练Long-CoT Cold StartReasoning RLThinking Mode FusionGeneral RLStrong-to-Weak Distillation 模型结构…

【网络编程】十、详解 UDP 协议

文章目录 Ⅰ. 传输层概述1、进程之间的通信2、再谈端口号端口号的引出五元组标识一个通信端口号范围划分常见的知名端口号查看知名端口号协议号 VS 端口号 3、两个问题一个端口号是否可以被多个进程绑定&#xff1f;一个进程是否可以绑定多个端口号&#xff1f; 4、部分常见指令…

实现RTSP低延迟播放器,挑战与解决方案

随着低延迟直播需求的快速增长&#xff0c;RTSP&#xff08;Real-Time Streaming Protocol&#xff09;播放器逐渐成为实时视频流传输中的核心技术之一。与WebRTC&#xff08;Web Real-Time Communication&#xff09;相比&#xff0c;RTSP在实时性和网络延迟方面面临诸多挑战&…

【springcloud学习(dalston.sr1)】Eureka单个服务端的搭建(含源代码)(三)

该系列项目整体介绍及源代码请参照前面写的一篇文章【springcloud学习(dalston.sr1)】项目整体介绍&#xff08;含源代码&#xff09;&#xff08;一&#xff09; springcloud学习&#xff08;dalston.sr1&#xff09;系统文章汇总如下&#xff1a; 【springcloud学习(dalston…

GPU与NPU异构计算任务划分算法研究:基于强化学习的Transformer负载均衡实践

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 引言 在边缘计算与AI推理场景中&#xff0c;GPU-NPU异构计算架构已成为突破算力瓶颈的关键技…