#include "FfmpegDecodeNew.h" FfmpegDecodeNew::FfmpegDecodeNew(QObject* parent) : QThread(parent) , m_bNeedWork(false) , m_pConstBuffer(nullptr) , m_pAVPacket(nullptr) , m_pAVCodec(nullptr) , m_pAVCodecParserContext(nullptr) , m_pAVCodecContext(nullptr) , m_pAVFrameSrc(nullptr) , m_pAVFrameDes(nullptr) , m_pSwsContext(nullptr) , m_bSwsContext(false) , m_bImageUpdated(false) , m_iWidth(0) // 图像宽度 , m_iHeight(0) // 图像高度 { m_pConstBuffer = new ConstBuffer(VideoBufferLength, false, false, VideoPacketLength); } FfmpegDecodeNew::~FfmpegDecodeNew() { if (m_pConstBuffer) { delete m_pConstBuffer; m_pConstBuffer = nullptr; } } void FfmpegDecodeNew::setParam(unsigned short format, int width, int height) { m_usFormat = format; m_iWidth = width; m_iHeight = height; switch (m_usFormat) { case 1: // 444P m_AVPixelFormat = AV_PIX_FMT_YUV444P; break; case 2: // 422P m_AVPixelFormat = AV_PIX_FMT_YUV422P; break; case 3: // 420P m_AVPixelFormat = AV_PIX_FMT_YUV420P; break; case 4: // NV12 m_AVPixelFormat = AV_PIX_FMT_NV12; break; case 5: // RGB24 m_AVPixelFormat = AV_PIX_FMT_RGB24; break; default: break; } } void FfmpegDecodeNew::init() { // (1)注册所有编解码器(codecs)、解析器(parsers)以及码流过滤器(bitstream filters) avcodec_register_all(); // (2)申请分配压缩数据包空间 m_pAVPacket = av_packet_alloc(); if (!m_pAVPacket) { // 申请分配压缩数据包空间失败 return; } // (3)查找H264压缩格式视频解码器 m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!m_pAVCodec) { // 未找到编解码器 return; } // (4)查找解析器 m_pAVCodecParserContext = av_parser_init(m_pAVCodec->id); if (!m_pAVCodecParserContext) { // 未找到解析器 return; } // (5)分配视频编解码器上下文 m_pAVCodecContext = avcodec_alloc_context3(m_pAVCodec); if (!m_pAVCodecContext) { // 无法分配视频编解码器上下文 return; } // (6)打开解码器 if (avcodec_open2(m_pAVCodecContext, m_pAVCodec, NULL) < 0) { return; } // (7)申请视频帧 m_pAVFrameSrc = av_frame_alloc(); if (!m_pAVFrameSrc) { // 申请视频帧存储空间失败 return; } av_image_alloc(m_pAVFrameSrc->data, m_pAVFrameSrc->linesize, m_iWidth, m_iHeight, m_AVPixelFormat, 1); // (11)申请转换后视频帧 m_pAVFrameDes = av_frame_alloc(); if (!m_pAVFrameDes) { return; } av_image_alloc(m_pAVFrameDes->data, m_pAVFrameDes->linesize, m_iWidth, m_iHeight, AV_PIX_FMT_RGB24, 1); /* int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, m_iWidth, m_iHeight); uint8_t* pBuffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t)); m_pAVFrameDes = av_frame_alloc(); m_pAVFrameDes->data[0] = pBuffer; avpicture_fill((AVPicture*)m_pAVFrameDes, pBuffer, AV_PIX_FMT_RGB24, m_iWidth, m_iHeight); */ // (12)初始化图像格式转换 /*m_pSwsContext = sws_getContext(m_iWidth, m_iHeight, m_AVPixelFormat, m_iWidth, m_iHeight, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);*/ m_pSwsContext = sws_getContext(m_iWidth, m_iHeight, (AVPixelFormat)m_AVPixelFormat, m_iWidth, m_iHeight, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); } void FfmpegDecodeNew::run() { m_bNeedWork = true; unsigned short usRecvSize = 0; unsigned char* pVideoBuffer = new unsigned char[VideoPacketLength]; int ret = 0; while (m_bNeedWork) { usRecvSize = m_pConstBuffer->read(pVideoBuffer, VideoPacketLength); if (usRecvSize <= 0) { continue; } unsigned char* pBuffer = pVideoBuffer; while (0 < usRecvSize) { // (8)获取AVPacket压缩数据 ret = av_parser_parse2(m_pAVCodecParserContext, m_pAVCodecContext, &(m_pAVPacket->data), &(m_pAVPacket->size), pBuffer, usRecvSize, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); if (ret < 0) { return; } pBuffer += ret; usRecvSize -= ret; if (m_pAVPacket->size) { // 说明获取到AVPacket压缩数据 decode(m_pAVCodecContext, m_pAVFrameSrc, m_pAVPacket); } } } } void FfmpegDecodeNew::decode(AVCodecContext* pCodecContext, AVFrame* pFrame, AVPacket* pPacket) { // (9)发送AVPacket数据到Ffmepg,放到解码队列中 int ret = avcodec_send_packet(pCodecContext, pPacket); if (ret < 0) { return; } while (0 <= ret) { // (10)从解码队列中取出1个AVFrame数据 ret = avcodec_receive_frame(pCodecContext, pFrame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { return; } else if (ret < 0) { return; } /* //验证一下是否可以根据pFrame对m_pAVFrameDes操作av_image_alloc和sws_getContext if (m_bSwsContext == false) { av_image_alloc(m_pAVFrameDes->data, m_pAVFrameDes->linesize, pFrame->width, pFrame->height, AV_PIX_FMT_RGB24, 1); //(12)初始化图像格式转换 m_pSwsContext = sws_getContext(pFrame->width, pFrame->height, (AVPixelFormat)pFrame->format, pFrame->width, pFrame->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL); m_iWidth = pFrame->width; //图像宽度 m_iHeight = pFrame->height; //图像高度 m_bSwsContext = true; } if (m_bSwsContext == true) { // (13) 进行图像格式转换 sws_scale(m_pSwsContext, m_pAVFrameSrc->data, m_pAVFrameSrc->linesize, 0, m_pAVFrameSrc->height, m_pAVFrameDes->data, m_pAVFrameDes->linesize); //(14)对转换后的数据进行处理 m_bImageUpdated = true; m_image = QImage((uchar*)m_pAVFrameDes->data[0], m_iWidth,m_iHeight,QImage::Format_RGB888); } */ // (13) 进行图像格式转换 sws_scale(m_pSwsContext, pFrame->data, pFrame->linesize, 0, pCodecContext->height, m_pAVFrameDes->data, m_pAVFrameDes->linesize); // (14)对转换后的数据进行处理 QMutexLocker locker(&m_mutex); m_bImageUpdated = true; m_image = QImage((uchar*)m_pAVFrameDes->data[0], m_iWidth, m_iHeight, QImage::Format_RGB888); } } bool FfmpegDecodeNew::getImage(QImage& image) { QMutexLocker locker(&m_mutex); if (m_bImageUpdated) { image = m_image; m_bImageUpdated = false; return true; } return false; }