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一帧,绝大多数场景够用了。

相关推荐
嘟嘟实验室3 小时前
微信小程序xr-frame透明视频实现
微信小程序·ffmpeg·音视频·xr
泰勒朗斯7 小时前
如何编译Opencv +ffmpeg linux 明明安装了ffmpeg但是opencv就是找不到
linux·opencv·ffmpeg
-Mr_X-13 小时前
windows下srs流媒体服务器使用ffmpeg推流
ffmpeg
dvlinker14 小时前
C++开源项目 VLC 源代码的交叉编译以及库的裁剪方法详解
ffmpeg·mingw-w64·msys2·cygwin·开源vlc·vlc编译·vlc裁剪
因我你好久不见1 天前
springboot java ffmpeg 视频压缩、提取视频帧图片、获取视频分辨率
java·spring boot·ffmpeg
cuijiecheng20182 天前
音视频入门基础:MPEG2-TS专题(21)——FFmpeg源码中,获取TS流的视频信息的实现
ffmpeg·音视频
cuijiecheng20182 天前
音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现
ffmpeg·音视频·aac
流氓也是种气质 _Cookie2 天前
uniapp blob格式转换为video .mp4文件使用ffmpeg工具
ffmpeg·uni-app
野蛮的大西瓜2 天前
BigBlueButton视频会议 vs 华为云会议的详细对比
人工智能·自动化·音视频·实时音视频·信息与通信·视频编解码
网络安全queen2 天前
网络安全-企业环境渗透2-wordpress任意文件读&&FFmpeg任意文件读
安全·web安全·ffmpeg