#include "Transcode.h" #include "LHQLogAPI.h" extern "C" { #include "libavcodec/avcodec.h" #include "libswscale/swscale.h" #include "libavutil/pixfmt.h" #include "libavutil/imgutils.h" } TransCode::TransCode() { } TransCode::~TransCode() { if(m_swsCtx != nullptr) { sws_freeContext(m_swsCtx); m_swsCtx = nullptr; } } /* 使用ffmpeg将yv12转换成RGB24 */ // bool YV12ToRGB24_FFmpeg(unsigned char *pYV12Data, unsigned char *pRGB24Data, int width, int height) // { // if (width < 1 || height < 1 || pYV12Data == NULL || pRGB24Data == NULL) // return false; // //int srcNumBytes,dstNumBytes; // //uint8_t *pSrc,*pDst; // AVPicture pFrameYUV, pFrameBGR; // //pFrameYUV = avpicture_alloc(); // //srcNumBytes = avpicture_get_size(PIX_FMT_YUV420P,width,height); // //pSrc = (uint8_t *)malloc(sizeof(uint8_t) * srcNumBytes); // avpicture_fill(&pFrameYUV, pYV12Data, AV_PIX_FMT_YUV420P, width, height); // //U,V互换 // uint8_t * ptmp=pFrameYUV.data[1]; // pFrameYUV.data[1]=pFrameYUV.data[2]; // pFrameYUV.data [2]=ptmp; // //pFrameBGR = avcodec_alloc_frame(); // //dstNumBytes = avpicture_get_size(PIX_FMT_BGR24,width,height); // //pDst = (uint8_t *)malloc(sizeof(uint8_t) * dstNumBytes); // avpicture_fill(&pFrameBGR, pRGB24Data, AV_PIX_FMT_BGR24, width,height); // struct SwsContext* imgCtx = NULL; // imgCtx = sws_getContext(width,height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_BGR24,SWS_BILINEAR, 0, 0, 0); // if (imgCtx != NULL){ // sws_scale(imgCtx,pFrameYUV.data,pFrameYUV.linesize,0,height,pFrameBGR.data,pFrameBGR.linesize); // if(imgCtx){ // sws_freeContext(imgCtx); // imgCtx = NULL; // } // return true; // } // else{ // sws_freeContext(imgCtx); // imgCtx = NULL; // return false; // } // } bool TransCode::YV12ToRGB24_FFmpeg(unsigned char *pYV12Data, unsigned char *pRGB24Data, int width, int height) { int ret = 0; /* 创建AVFrame */ AVFrame* pFrameYV12 = av_frame_alloc(); AVFrame* pFrameBGR = av_frame_alloc(); /* 将pFrameYV12与pYV12Data相关联 */ ret = av_image_fill_arrays(pFrameYV12->data, pFrameYV12->linesize, pYV12Data, AV_PIX_FMT_YUV420P, width, height, 1); if(ret < 0) { av_frame_free(&pFrameYV12); av_frame_free(&pFrameBGR); return false; } /* UV互换,海康的UV是反的 */ uint8_t* pTmp = pFrameYV12->data[1]; pFrameYV12->data[1] = pFrameYV12->data[2]; pFrameYV12->data[2] = pTmp; /* 将pFrameBGR和数组pRGB24Data关联起来 */ // ret = av_image_fill_arrays(pFrameBGR->data, pFrameBGR->linesize, pRGB24Data, AV_PIX_FMT_BGR24, width, height, 1); ret = av_image_fill_arrays(pFrameBGR->data, pFrameBGR->linesize, pRGB24Data, AV_PIX_FMT_RGB24, width, height, 1); if(ret < 0) { av_frame_free(&pFrameYV12); av_frame_free(&pFrameBGR); return false; } /* 获取转码上下文 */ if(m_swsCtx == nullptr) { m_swsCtx = sws_getCachedContext(m_swsCtx, width, height, /* 原图像大小和格式 */ AV_PIX_FMT_YUV420P, /* 输入图像的像素格式 */ width, height, /* 目标图像的大小 */ AV_PIX_FMT_RGB24, /* 目标图像的格式 */ SWS_BILINEAR, /* 图像缩放算法,双线性 */ nullptr, /* 输入图像的滤波器信息,不需要传NULL */ nullptr, /* 输出图像的滤波器信息,不需要传NULL */ nullptr); /* 特定缩放算法需要的参数,不需要传NULL */ } /* 转换图像 */ bool result = false; if(m_swsCtx != nullptr) { sws_scale(m_swsCtx, pFrameYV12->data, pFrameYV12->linesize, 0, height, pFrameBGR->data, pFrameBGR->linesize); result = true; }else { LH_WRITE_ERROR(QString("获取转码上下文失败")); result = false; } /* 释放资源 */ av_frame_free(&pFrameYV12); av_frame_free(&pFrameBGR); return result; } /* YV12转RGB888 */ void TransCode::YV12ToRGB888(unsigned char *pYV12Data, unsigned char *pRGB24Data, int width, int height) { int ySize = width * height; int uvSize = ySize / 4; const uint8_t* yData = pYV12Data; const uint8_t* vData = pYV12Data + ySize; const uint8_t* uData = pYV12Data + ySize + uvSize; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int yIndex = y * width + x; int uvIndex = (y / 2) * (width / 2) + (x / 2); uint8_t Y = yData[yIndex]; uint8_t U = uData[uvIndex]; uint8_t V = vData[uvIndex]; // YUV 转 RGB int R = Y + 1.403 * (V - 128); int G = Y - 0.344 * (U - 128) - 0.714 * (V - 128); int B = Y + 1.770 * (U - 128); // 限制范围 [0, 255] R = std::min(std::max(R, 0), 255); G = std::min(std::max(G, 0), 255); B = std::min(std::max(B, 0), 255); // 存储 RGB 数据 int rgbIndex = yIndex * 3; pRGB24Data[rgbIndex] = static_cast(R); pRGB24Data[rgbIndex + 1] = static_cast(G); pRGB24Data[rgbIndex + 2] = static_cast(B); } } } /* RGB888转QImage */ void TransCode::YV12ToQImage(unsigned char *pYV12Data, Image_QImage& image, int width, int height) { unsigned char* rgbData = new unsigned char [width * height * 3]; // YV12ToRGB888(pYV12Data, rgbData, width, height); if(YV12ToRGB24_FFmpeg(pYV12Data, rgbData, width, height)) { image.image = QImage(rgbData, width, height, QImage::Format_RGB888); image.width = width; image.height = height; }else { LH_WRITE_ERROR("YV12ToRGB24_FFmpeg failed!"); } /* 释放资源 */ delete [] rgbData; } /* YV12转YUV420 */ void TransCode::YV12ToYUV420(unsigned char *pYV12Data, Image_YUV420& yuvData, int width, int height) { int y_size = width * height; int uv_size = y_size / 4; // 分配 YUV 数据的空间 yuvData.yData.resize(y_size); yuvData.uData.resize(uv_size); yuvData.vData.resize(uv_size); // 提取 Y、V、U 分量,交换uv分量,海康的uv是反的 const uint8_t* y = pYV12Data; const uint8_t* v = pYV12Data + y_size; const uint8_t* u = pYV12Data + y_size + uv_size; // 复制 Y 分量 // std::memcpy(yuvData.yData.data(), y, y_size); yuvData.yData.append((char*)y, y_size); // 复制 U 分量 yuvData.uData.append((char*)v, uv_size); // uint8_t* yuv_u = (uint8_t*)yuvData.uData.data() + y_size; // for (int i = 0; i < uv_size; ++i) { // yuv_u[i] = u[i]; // } // 复制 V 分量 yuvData.vData.append((char*)u, uv_size); // uint8_t* yuv_v = (uint8_t*)yuvData.vData.data() + y_size + uv_size; // for (int i = 0; i < uv_size; ++i) { // yuv_v[i] = v[i]; // } }