|
|
|
@ -1,18 +1,6 @@
|
|
|
|
|
#include "decodestream.h"
|
|
|
|
|
|
|
|
|
|
DecodeStream::DecodeStream(QObject *parent) : QObject{parent} {
|
|
|
|
|
/************* 获取当前环境支持的硬件解码器 **************/
|
|
|
|
|
AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
|
|
|
|
|
QStringList strTypes;
|
|
|
|
|
while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) {
|
|
|
|
|
m_HWDeviceTypes.append(type);
|
|
|
|
|
const char *ctype = av_hwdevice_get_type_name(type);
|
|
|
|
|
if (ctype) {
|
|
|
|
|
strTypes.append(QString(ctype));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "支持的硬件解码器:" << strTypes;
|
|
|
|
|
}
|
|
|
|
|
DecodeStream::DecodeStream(QObject *parent) : QObject{parent} {}
|
|
|
|
|
|
|
|
|
|
bool DecodeStream::init(AVPacketQueueManager *queueManager,
|
|
|
|
|
AVFormatContext *formatContext, int videoIndex) {
|
|
|
|
@ -63,14 +51,6 @@ void DecodeStream::close() {
|
|
|
|
|
qDebug() << "decode Stream close!" << m_start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 设置是否使用硬件解码
|
|
|
|
|
* @param flag true:使用 false:不使用
|
|
|
|
|
*/
|
|
|
|
|
void DecodeStream::setHWDecoder(bool flag) {
|
|
|
|
|
m_HWDecoder = flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DecodeStream::initObject() {
|
|
|
|
|
// 分配AVFrame并将其字段设置为默认值。
|
|
|
|
|
m_frame = av_frame_alloc();
|
|
|
|
@ -79,16 +59,6 @@ bool DecodeStream::initObject() {
|
|
|
|
|
free();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_frameHW = av_frame_alloc();
|
|
|
|
|
if (!m_frameHW) {
|
|
|
|
|
#if PRINT_LOG
|
|
|
|
|
qWarning() << "av_frame_alloc() Error!";
|
|
|
|
|
#endif
|
|
|
|
|
free();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -137,11 +107,6 @@ bool DecodeStream::initDecoder(AVFormatContext *inputFormatContext,
|
|
|
|
|
// m_codecContext->err_recognition = AV_EF_IGNORE_ERR;
|
|
|
|
|
// m_codecContext->flags |= AV_CODEC_FLAG2_CHUNKS;
|
|
|
|
|
|
|
|
|
|
if (m_HWDecoder) {
|
|
|
|
|
// 初始化硬件解码器(在avcodec_open2前调用)
|
|
|
|
|
initHWDecoder(codec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化解码器上下文,如果之前avcodec_alloc_context3传入了解码器,这里设置NULL就可以
|
|
|
|
|
ret = avcodec_open2(m_codecContext, codec, nullptr);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
@ -173,12 +138,6 @@ AVFrame *DecodeStream::decodePacket(AVPacket *inputPacket) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_frameTemp = m_frame;
|
|
|
|
|
if (!m_frame->data[0]) {
|
|
|
|
|
m_frameTemp = m_frameHW;
|
|
|
|
|
if (!dataCopy()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return m_frameTemp;
|
|
|
|
|
// QThread::msleep(1);
|
|
|
|
|
}
|
|
|
|
@ -203,101 +162,10 @@ void DecodeStream::free() {
|
|
|
|
|
if (m_codecContext) {
|
|
|
|
|
avcodec_free_context(&m_codecContext);
|
|
|
|
|
}
|
|
|
|
|
if (hw_device_ctx) {
|
|
|
|
|
av_buffer_unref(&hw_device_ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_frame) {
|
|
|
|
|
av_frame_free(&m_frame);
|
|
|
|
|
}
|
|
|
|
|
if (m_frameHW) {
|
|
|
|
|
av_frame_free(&m_frameHW);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********** FFmpeg获取GPU硬件解码帧格式的回调函数 ***************/
|
|
|
|
|
static enum AVPixelFormat g_pixelFormat;
|
|
|
|
|
/**
|
|
|
|
|
* @brief 回调函数,获取GPU硬件解码帧的格式
|
|
|
|
|
* @param s
|
|
|
|
|
* @param fmt
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
AVPixelFormat get_hw_format(AVCodecContext *s, const enum AVPixelFormat *fmt) {
|
|
|
|
|
Q_UNUSED(s)
|
|
|
|
|
const enum AVPixelFormat *p;
|
|
|
|
|
|
|
|
|
|
for (p = fmt; *p != -1; p++) {
|
|
|
|
|
if (*p == g_pixelFormat) {
|
|
|
|
|
return *p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "无法获取硬件表面格式.";
|
|
|
|
|
return AV_PIX_FMT_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 初始化硬件解码器
|
|
|
|
|
* @param codec
|
|
|
|
|
*/
|
|
|
|
|
bool DecodeStream::initHWDecoder(const AVCodec *codec) {
|
|
|
|
|
if (!codec) return false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0;; i++) {
|
|
|
|
|
const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i);
|
|
|
|
|
if (!config) {
|
|
|
|
|
qDebug() << "打开硬件解码器失败!";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) {
|
|
|
|
|
for (auto i : m_HWDeviceTypes) {
|
|
|
|
|
if (config->device_type == AVHWDeviceType(i)) {
|
|
|
|
|
g_pixelFormat = config->pix_fmt;
|
|
|
|
|
|
|
|
|
|
// 打开指定类型的设备,并为其创建AVHWDeviceContext。
|
|
|
|
|
int ret = av_hwdevice_ctx_create(&hw_device_ctx,
|
|
|
|
|
config->device_type,
|
|
|
|
|
nullptr, nullptr, 0);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
showError(ret);
|
|
|
|
|
free();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "打开硬件解码器:"
|
|
|
|
|
<< av_hwdevice_get_type_name(config->device_type);
|
|
|
|
|
m_codecContext->hw_device_ctx =
|
|
|
|
|
av_buffer_ref(hw_device_ctx);
|
|
|
|
|
m_codecContext->get_format = get_hw_format;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 硬件解码完成需要将数据从GPU复制到CPU
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
bool DecodeStream::dataCopy() {
|
|
|
|
|
if (m_frame->format != g_pixelFormat) {
|
|
|
|
|
av_frame_unref(m_frame);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#if 1
|
|
|
|
|
int ret = av_hwframe_map(m_frameHW, m_frame, 0);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
showError(ret);
|
|
|
|
|
av_frame_unref(m_frame);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_frameHW->width = m_frame->width;
|
|
|
|
|
m_frameHW->height = m_frame->height;
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DecodeStream::isValidAVFrame(AVFrame *frame) {
|
|
|
|
|