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

相关推荐
追光天使1 天前
Mac M1 源码安装FFmpeg,开启enable-gpl 和 lib x264
macos·ffmpeg
cuijiecheng20182 天前
FFmpeg源码:av_base64_decode函数分析
ffmpeg
soonlyai2 天前
Windows平台最新视频号内容下载工具(MP4格式一键解析)
人工智能·经验分享·产品运营·音视频·流量运营·视频编解码·视频
2035去旅行2 天前
FFmpeg(7.1版本)编译:Ubuntu18.04交叉编译到ARM
arm开发·ffmpeg
我码玄黄2 天前
FFmpeg:多媒体处理的瑞士军刀
后端·ffmpeg·开源
yerennuo2 天前
FFmpeg rtmp推流直播
ffmpeg
2035去旅行2 天前
FFmpeg(7.1版本)的基本组成
ffmpeg
学习嵌入式的小羊~4 天前
RV1126画面质量三:QP调节
ffmpeg·音视频
daqinzl4 天前
Ubuntu x64下交叉编译ffmpeg、sdl2到目标架构为aarch64架构的系统(生成ffmpeg、ffprobe、ffplay)
ubuntu·ffmpeg·ffplay·sdl2·交叉编译 aarch64
yerennuo5 天前
FFmpeg 自定义IO和格式转换
ffmpeg