firefly rk3399使用ffmpeg硬解码

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

注意:这篇文章仅针对firefly设备,我在rk3399上操作成功,理论上也适合rk356x或358x系列的,我手上没有这些设备,所以没法测试。

今天这个方法比较简单,使用起来也有些限制,但是对于很多人来说够用了。

Device:firefly rk3399

OS:Ubuntu-20.04,Ubuntu-18.04


一、准备一个firefly的rk3399

为什么一定要是firefly的呢?首先我手上只有firefly的设备,其次这个方法要使用firefly的软件源。

二、使用步骤

1.检查ffmpeg版本

没错,这个方法比直接使用mpp简单,它将mpp和ffmpeg结合了起来,操作也大大简化。前提是ffmpeg的版本必须是firefly编译的版本。

bash 复制代码
ffmpeg

ffmpeg version 4.2.4-1ubuntu1.0firefly3 Copyright (c) 2000-2020 the FFmpeg developers

ffmpeg版本带firefly字样就是对的,如果你删除了firefly的源或者重新装过ffmpeg就不行。如果你属于前者就跳过下一步,如果你属于后者不妨往下看:

1.查看源

bash 复制代码
ls /etc/apt/source.list.d/

cat /etc/apt/source.list

如果是Ubuntu-18.04那么源是作为文件存放在/etc/apt/source.list.d/的,如果是Ubuntu-20.04源是作为条目放在/etc/apt/source.list文件里面的。

bash 复制代码
deb http://wiki.t-firefly.com/firefly-ubuntu-repo focal main

如果你没有firefly的源,或者删掉了就重新加上就行了,切记备份数据可能覆盖!

2.查看解码器

确认ffmpeg支持我们需要的解码器:h264_rkmpphevc_rkmpp

bash 复制代码
ffmpeg -decoders | grep rkmpp

V..... h264_rkmpp           h264 (rkmpp) (codec h264)
 V..... hevc_rkmpp           hevc (rkmpp) (codec hevc)
 V..... vp8_rkmpp            vp8 (rkmpp) (codec vp8)
 V..... vp9_rkmpp            vp9 (rkmpp) (codec vp9)

查看下是否有我们需要的条目,正常情况下应该是上面的4种。

注意:只有支持上面的4种你才能硬解码,否则不支持这种方式!

3.解码代码

前提是上面的你处理好了,接下来就开始写解码代码了。

main.cpp

cpp 复制代码
#include <iostream>

#ifdef __cplusplus
extern "C"
{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#ifdef __cplusplus
};
#endif

using namespace std;

int main(){

	AVFormatContext *formatContext = avformat_alloc_context();
	AVCodecContext *codecContext = nullptr;
	AVCodec *codec = nullptr;
	AVFrame *mpp_frame = av_frame_alloc();
	AVPacket *packet = av_packet_alloc();
	string hw_codec_name;//区分h264_rkmpp和hevc_rkmpp的
	
	int videoStreamIndex = -1;

	//替换本地视频,rtsp原理差不多,唯一的差别是需要初始化网络模块并设备一些网络参宿,这个网上随便能找到
	avformat_open_input(&formatContext, "../1920x1080.mp4", nullptr, nullptr);
    avformat_find_stream_info(formatContext, nullptr);

	//找出视频的video index,音频也一样
	//确定视频编码类型h264或hevc等等,vp8和vp9同理
    for (int i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            if (formatContext->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264) {
                printf("video stream is H264\n");
                hw_codec_name.assign("h264_rkmpp");
            } else if (formatContext->streams[i]->codecpar->codec_id == AV_CODEC_ID_HEVC) {
                printf("video stream is HEVC\n");
                hw_codec_name.assign("hevc_rkmpp");
            } else {
                printf("video stream is Unknown!\n");
                exit(1);
            }
            break;
        }
    }

	//找到匹配的解码器,h264对应h264_rkmpp,hevc对应hevc_rkmpp,vp8和vp9同理
    codec = avcodec_find_decoder_by_name(hw_codec_name.c_str());
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }


	//创建解码器上下文
    codecContext = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar);
    avcodec_open2(codecContext, codec, nullptr);
	
	printf("Stream video width is %d height is %d\n", codecContext->width, codecContext->height);
	    while (av_read_frame(formatContext, packet) >= 0) {
        if (packet->stream_index == videoStreamIndex) {
            int response = avcodec_send_packet(codecContext, packet);
            if (response >= 0) {
            	//一个packet可能包含几帧,这里需要循环取,直到取完为止,一个frame就是一张图片
                while (avcodec_receive_frame(codecContext, mpp_frame) == 0) {
                	//YUV格式是YUV420P,内存中排列方式是先Y再U再V,这里不细说了查下百科就知道了。
                    printf("y: %d, u: %d, v: %d\n", mpp_frame->linesize[0], mpp_frame->linesize[1],
                           mpp_frame->linesize[2]);
                }
            }
        }
        av_packet_unref(packet);
    }
    avcodec_free_context(&codecContext);
    avformat_close_input(&formatContext);
    av_frame_free(&mpp_frame);
    av_packet_free(&packet);
	return 0;
}

CmakeLists.txt

bash 复制代码
cmake_minimum_required(VERSION  3.10 FATAL_ERROR)

project(MPP)

set(CMAKE_CXX_STANDARD 11)

find_package(Threads REQUIRED)

add_executable(MPP
		main.cpp
)
target_link_libraries(MPP Threads::Threads)
target_link_libraries(MPP rockchip_mpp)
target_link_libraries(MPP avcodec avformat avutil)

编译运行就可以了。


总结

1、实测1080p解码是5-6ms一帧,绝大多数场景够用了。

相关推荐
EasyCVR2 小时前
EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?
人工智能·算法·ffmpeg·音视频·webrtc·监控视频接入
简鹿办公3 小时前
使用 FFmpeg 进行音视频转换的相关命令行参数解释
ffmpeg·简鹿视频格式转换器·ffmpeg视频转换
安步当歌5 小时前
【WebRTC】视频编码链路中各个类的简单分析——VideoStreamEncoder
音视频·webrtc·视频编解码·video-codec
EasyCVR7 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
runing_an_min7 小时前
ffmpeg 视频滤镜:屏蔽边框杂色- fillborders
ffmpeg·音视频·fillborders
岁月小龙17 小时前
如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
ffmpeg·origin·ffprobe·rpath
安步当歌20 小时前
【WebRTC】视频采集模块中各个类的简单分析
音视频·webrtc·视频编解码·video-codec
行者记2 天前
ffmpeg命令——从wireshark包中的rtp包中分离h264
测试工具·ffmpeg·wireshark
EasyCVR2 天前
国标GB28181视频平台EasyCVR私有化视频平台工地防盗视频监控系统方案
运维·科技·ffmpeg·音视频·1024程序员节·监控视频接入
hypoqqq2 天前
使用ffmpeg播放rtsp视频流
ffmpeg