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 天前
音视频播放的核心处理流程
ffmpeg
Industio_触觉智能1 天前
【开源鸿蒙-AVCodec Kit】音视频编解码封装解封装部件介绍,转自开源鸿蒙官媒OpenAtom OpenHarmony
harmonyos·视频编解码·openharmony·开源鸿蒙
mortimer2 天前
搞懂FFmpeg中2个桀骜不驯的参数:CRF 与 Preset
ffmpeg·音视频开发·视频编码
DogDaoDao2 天前
OpenCV音视频编解码器详解
人工智能·opencv·音视频·视频编解码·h264·h265·音视频编解码
2401_841495643 天前
Windows 系统中ffmpeg安装问题的彻底解决
windows·python·ffmpeg·bug·语音识别·下载·安装步骤
八月的雨季 最後的冰吻3 天前
FFmpeg --15-视频解码: AVIO内存输入模式分析
ffmpeg·音视频
aqi003 天前
FFmpeg开发笔记(八十八)基于Compose的国产电视直播开源框架MyTV
android·ffmpeg·音视频·直播·流媒体
present12273 天前
一段音频/视频分离成人声与伴奏,Windows + Anaconda 快速跑通 Spleeter(离线可用)
windows·职场和发展·ffmpeg·音视频·娱乐·媒体
fxshy4 天前
python使用ffmpeg对视频进行转码
python·ffmpeg·音视频
zhangzhangkeji4 天前
FFMPEG - 6:合并、提取音视频;截取、连接音视频,
ffmpeg·音视频