热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

x264及H264实现对OpenCVMat的编解码

x264及H264实现对OpenCVMat的编解码微信公众号:幼儿园的学霸个人的学习笔记,关于OpenCV,关于机器学习,…。问题或建议,
x264及H264实现对OpenCV Mat的编解码

微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;

之前写的ADAS客户端软件和ADAS程序之间的视频传输采用了cv::imencode和cv::imdecode函数实现编解码,最近偶然间发现可以利用H.264对视频进行编解码,并且效果还不错,特此记录。

目录

文章目录

  • x264及H264实现对OpenCV Mat的编解码
  • 目录
  • x264对Mat进行编码
  • H264对Mat进行编码
  • H264对x264/H264编码数据进行解码
  • 编码+解码示例
    • x264编码+H264解码示例
    • H264编码+H264解码示例


x264对Mat进行编码

代码如下.使用时,首先进行编码器的初始化,然后在while循环中调用编码函数实现编码;如果需要进行网络传输,发送编码后的数据即可,在接收端,采用H264进行解码,恢复视频信息。

  • x264_encoder.h

//
// Created by liheng on 19-12-9.
//https://www.cnblogs.com/ziyu-trip/p/7075003.html#ifndef ADAS_X264_ENCODER_H
#define ADAS_X264_ENCODER_H#include
#include "x264.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"struct x264_encoder{x264_param_t param;char preset[20];char tune[20];char profile[20];x264_t* h;x264_picture_t pic_in;x264_picture_t pic_out;long colorspace;x264_nal_t* nal;int iframe;int iframe_size;int inal;
};class x264Encoder
{
public:x264Encoder();x264Encoder(int videoWidth, int videoHeight, int channel, int fps);~x264Encoder();/** 创建X264编码器* @param[in] videoWidth 视频宽度* @param[in] videoHeight 视频高度* @param[in] fps 帧率* @return 成功返回true, 失败返回false.*/bool Create(int videoWidth, int videoHeight, int channel = 3, int fps = 30);/** 编码一帧* @param[in] frame 输入的一帧图像* @return 返回编码后数据尺寸, 0表示编码失败*/int EncodeOneFrame(const cv::Mat& frame);/** 获取编码后的帧数据* 说明: EncodeOneFrame 后调用* @return 返回裸x264数据*/uchar* GetEncodedFrame() const;/** 销毁X264编码器*/void Destory();// 编码器是否可用bool IsValid() const;private:void Init();public:int m_width;int m_height;int m_channel;int m_fps;protected:int m_widthstep;int m_lumaSize;int m_chromaSize;x264_encoder* m_encoder;
};#endif //ADAS_X264_ENCODER_H

  • x264_encoder.cpp

//
// Created by liheng on 19-12-9.
//#include "x264_encoder.h"
#include
#include
#include
#include
#include "opencv2/imgproc.hpp"#define ENCODER_TUNE "zerolatency"
#define ENCODER_PROFILE "baseline"
#define ENCODER_PRESET "veryfast"//"superfast"
#define ENCODER_COLORSPACE X264_CSP_I420
#define CLEAR(x) (memset((&x),0,sizeof(x)))x264Encoder::x264Encoder()
{Init();
}x264Encoder::x264Encoder(int videoWidth, int videoHeight, int channel, int fps)
{Init();Create(videoWidth, videoHeight, channel, fps);
}x264Encoder::~x264Encoder()
{Destory();
}void x264Encoder::Init()
{m_width = 0;m_height = 0;m_channel = 0;m_widthstep = 0;m_fps = 30;m_lumaSize = 0;m_chromaSize = 0;m_encoder = NULL;
}bool x264Encoder::Create(int videoWidth, int videoHeight, int channel, int fps)
{int ret;int imgSize;if (videoWidth <&#61; 0 || videoHeight <&#61; 0 || channel <0 || fps <&#61; 0){printf("wrong input param\n");return false;}m_width &#61; videoWidth;m_height &#61; videoHeight;m_channel &#61; channel;m_fps &#61; fps;m_widthstep &#61; videoWidth * channel;m_lumaSize &#61; m_width * m_height;m_chromaSize &#61; m_lumaSize / 4;imgSize &#61; m_lumaSize * channel;m_encoder &#61; (x264_encoder *)malloc(sizeof(x264_encoder));if (!m_encoder){printf("cannot malloc x264_encoder !\n");return false;}CLEAR(*m_encoder);m_encoder->iframe &#61; 0;m_encoder->iframe_size &#61; 0;strcpy(m_encoder->preset, ENCODER_PRESET);strcpy(m_encoder->tune, ENCODER_TUNE);/*初始化编码器*/CLEAR(m_encoder->param);x264_param_default(&m_encoder->param);ret &#61; x264_param_default_preset(&m_encoder->param, m_encoder->preset, m_encoder->tune);if (ret <0){printf("x264_param_default_preset error!\n");return false;}/*cpuFlags 去空缓冲区继续使用不死锁保证*/m_encoder->param.i_threads &#61; X264_SYNC_LOOKAHEAD_AUTO;/*视频选项*/m_encoder->param.i_csp &#61; X264_CSP_I420;m_encoder->param.i_width &#61; m_width; // 要编码的图像的宽度m_encoder->param.i_height &#61; m_height; // 要编码的图像的高度m_encoder->param.i_frame_total &#61; 0; // 要编码的总帧数&#xff0c;不知道用0m_encoder->param.i_keyint_max &#61; 10*fps;// 关键帧间隔/*流参数*/m_encoder->param.i_bframe &#61; 5;m_encoder->param.b_open_gop &#61; 0;m_encoder->param.i_bframe_pyramid &#61; 0;m_encoder->param.i_bframe_adaptive &#61; X264_B_ADAPT_TRELLIS;/*log参数&#xff0c;不需要打印编码信息时直接注释掉*/m_encoder->param.i_log_level &#61; X264_LOG_NONE;m_encoder->param.i_fps_num &#61; fps;//码率分子m_encoder->param.i_fps_den &#61; 1; //码率分母m_encoder->param.b_intra_refresh &#61; 1;m_encoder->param.b_annexb &#61; 1;m_encoder->param.rc.f_rf_constant &#61; 24;m_encoder->param.rc.i_rc_method &#61; X264_RC_CRF;/strcpy(m_encoder->profile, ENCODER_PROFILE);ret &#61; x264_param_apply_profile(&m_encoder->param, m_encoder->profile);if (ret <0){printf("x264_param_apply_profile error!\n");return false;}/*打开编码器*/m_encoder->h &#61; x264_encoder_open(&m_encoder->param);m_encoder->colorspace &#61; ENCODER_COLORSPACE;/*初始化pic*/ret &#61; x264_picture_alloc(&m_encoder->pic_in, m_encoder->colorspace, m_width, m_height);if ( ret <0 ){printf("x264_picture_alloc error! ret&#61;%d\n", ret);return false;}m_encoder->pic_in.img.i_csp &#61; m_encoder->colorspace;m_encoder->pic_in.img.i_plane &#61; 3;m_encoder->pic_in.i_type &#61; X264_TYPE_AUTO;m_encoder->inal &#61; 0;m_encoder->nal &#61; (x264_nal_t *)calloc(2, sizeof(x264_nal_t));if (!m_encoder->nal){printf("malloc x264_nal_t error!\n");return false;}CLEAR(*(m_encoder->nal));return true;
}int x264Encoder::EncodeOneFrame(const cv::Mat& frame)
{if (frame.empty()){return 0;}cv::Mat bgr(frame), yuv;if(1 &#61;&#61; frame.channels()){cv::cvtColor(frame, bgr, CV_GRAY2BGR);}cv::cvtColor(bgr, yuv, CV_BGR2YUV_I420);memcpy(m_encoder->pic_in.img.plane[0], yuv.data, m_lumaSize);memcpy(m_encoder->pic_in.img.plane[1], yuv.data &#43; m_lumaSize, m_chromaSize);memcpy(m_encoder->pic_in.img.plane[2], yuv.data &#43; m_lumaSize &#43; m_chromaSize, m_chromaSize);m_encoder->pic_in.i_pts &#61; m_encoder->iframe &#43;&#43;;m_encoder->iframe_size &#61; x264_encoder_encode(m_encoder->h, &m_encoder->nal, &m_encoder->inal, &m_encoder->pic_in, &m_encoder->pic_out);return m_encoder->iframe_size;
}uchar* x264Encoder::GetEncodedFrame() const
{return m_encoder->nal->p_payload;
}void x264Encoder::Destory()
{if (m_encoder){if (m_encoder->h){x264_encoder_close(m_encoder->h);m_encoder->h &#61; NULL;}free(m_encoder);m_encoder &#61; NULL;}
}bool x264Encoder::IsValid() const
{return ((m_encoder !&#61; NULL) && (m_encoder->h !&#61; NULL));
}

H264对Mat进行编码

代码如下&#xff0c;代码来源见代码说明。在原代码基础上进行了微调&#xff0c;以保证视频质量无损。

  • h264encoder.h

#ifndef _AV_H264_H_
#define _AV_H264_H_/***********************************************************
** Author:kaychan
** Data:2019-11-29
** Mail:1203375695&#64;qq.com
** Explain:a h264 codec
***********************************************************/#include #define __STDC_CONSTANT_MACROS
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
};
#endiftypedef struct AvH264EncConfig_T {int width &#61; 320;int height &#61; 240;int frame_rate &#61; 25;//int64_t bit_rate &#61; 320000;int gop_size &#61; 250;int max_b_frames &#61; 0;
}AvH264EncConfig;class h264Encoder {public:h264Encoder();~h264Encoder();int Init(AvH264EncConfig h264_config);AVPacket *encode(const cv::Mat& mat);void Destory();
private:AVCodec *cdc_;AVCodecContext *cdc_ctx_;AVFrame *avf_;AVPacket *avp_;int frame_size_;int pts_;
};#endif

  • h264encoder.cpp

#include "h264encoder.h"h264Encoder::h264Encoder() {cdc_ &#61; NULL;cdc_ctx_ &#61; NULL;avf_ &#61; NULL;avp_ &#61; NULL;
}h264Encoder::~h264Encoder()
{Destory();
}int h264Encoder::Init(AvH264EncConfig h264_config) {pts_ &#61; 0;cdc_ &#61; avcodec_find_encoder(AV_CODEC_ID_H264);if (!cdc_) {return -1;}cdc_ctx_ &#61; avcodec_alloc_context3(cdc_);if (!cdc_ctx_) {return -1;}//cdc_ctx_->bit_rate &#61; h264_config.bit_rate;//导致画面模糊cdc_ctx_->width &#61; h264_config.width;cdc_ctx_->height &#61; h264_config.height;cdc_ctx_->time_base &#61; { 1, h264_config.frame_rate };cdc_ctx_->framerate &#61; { h264_config.frame_rate, 1 };cdc_ctx_->gop_size &#61; h264_config.gop_size;cdc_ctx_->max_b_frames &#61; h264_config.max_b_frames;cdc_ctx_->pix_fmt &#61; AV_PIX_FMT_YUV420P;cdc_ctx_->codec_id &#61; AV_CODEC_ID_H264;cdc_ctx_->codec_type &#61; AVMEDIA_TYPE_VIDEO;//cdc_ctx_->qmin &#61; 10;//cdc_ctx_->qmax &#61; 51;//cdc_ctx_->qcompress &#61; 0.6;AVDictionary *dict &#61; nullptr;//av_dict_set(&dict, "preset", "slow", 0);av_dict_set(&dict, "preset", "veryfast", 0);av_dict_set(&dict, "tune", "zerolatency", 0);av_dict_set(&dict, "profile", "main", 0);avf_ &#61; av_frame_alloc();avp_ &#61; av_packet_alloc();if (!avf_ || !avp_) {return -1;}av_init_packet(avp_);frame_size_ &#61; cdc_ctx_->width * cdc_ctx_->height;avf_->format &#61; cdc_ctx_->pix_fmt;avf_->width &#61; cdc_ctx_->width;avf_->height &#61; cdc_ctx_->height;// alloc memoryint r &#61; av_frame_get_buffer(avf_, 0);if (r <0) {return -1;}r &#61; av_frame_make_writable(avf_);if (r <0) {return -1;}return avcodec_open2(cdc_ctx_, cdc_, &dict);
}void h264Encoder::Destory() {if(cdc_ctx_) avcodec_free_context(&cdc_ctx_);if (avf_) av_frame_free(&avf_);if (avp_) av_packet_free(&avp_);
}AVPacket *h264Encoder::encode(const cv::Mat& mat) {if (mat.empty()) return NULL;cv::resize(mat, mat, cv::Size(cdc_ctx_->width, cdc_ctx_->height));cv::Mat yuv;cv::cvtColor(mat, yuv, cv::COLOR_BGR2YUV_I420);unsigned char *pdata &#61; yuv.data;// fill yuv420// yyy yyy yyy yyy// uuu// vvvavf_->data[0] &#61; pdata;avf_->data[1] &#61; pdata &#43; frame_size_;avf_->data[2] &#61; pdata &#43; frame_size_ * 5 / 4;avf_->pts &#61; pts_&#43;&#43;;int r &#61; avcodec_send_frame(cdc_ctx_, avf_);if (r >&#61; 0) {r &#61; avcodec_receive_packet(cdc_ctx_, avp_);if (r &#61;&#61; 0) {avp_->stream_index &#61; avf_->pts;return avp_;}if (r &#61;&#61; AVERROR(EAGAIN) || r &#61;&#61; AVERROR_EOF) {return NULL;}}return NULL;
}

H264对x264/H264编码数据进行解码

  • h264decoder.h

#ifndef CH264DECODER_H
#define CH264DECODER_H#include
#include
//C&#43;&#43;引用C语言的头文件
extern "C"
{
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
}class CH264Decoder
{
public:CH264Decoder();~CH264Decoder();/*************************************************Function:initialDescription:初始化Input:无Output:无Return:错误代码Others:无*************************************************/int initial();/*************************************************Function:decodeDescription:解码Input:pDataIn-待解码数据&#xff0c;nInSize-待解码数据长度Output:pDataOut-解码后的数据&#xff0c;nWidth-解码后的图像宽度&#xff0c;nHeight-解码后的图像高度Return:错误代码Others:解码后的数据为RGB16格式*************************************************/int decode(uint8_t *pDataIn, int nInSize, cv::Mat& res);/*************************************************Function:unInitialDescription:销毁Input:无Output:无Return:无Others:无*************************************************/void unInitial();private:int avframe_to_cvmat(AVFrame *frame,cv::Mat& res);AVFrame *cvmat2avframe(cv::Mat mat);
private:AVCodec *codec;AVCodecContext *context;AVFrame *frame;AVPacket packet;};#endif // CH264DECODER_H

  • h264decoder.cpp

#include "h264decoder.h"CH264Decoder::CH264Decoder()
{initial();
}CH264Decoder::~CH264Decoder()
{unInitial();
}int CH264Decoder::initial()
{//avcodec_register_all();//新版本应该不需要这句话av_init_packet(&packet);codec &#61; avcodec_find_decoder(AV_CODEC_ID_H264);if (!codec){printf("avcodec_find_encoder failed");return -1;}context &#61; avcodec_alloc_context3(codec);if (!context){printf("avcodec_alloc_context3 failed");return -2;}context->codec_type &#61; AVMEDIA_TYPE_VIDEO;context->pix_fmt &#61; AV_PIX_FMT_YUV420P;if (avcodec_open2(context, codec, NULL) <0){printf("avcodec_open2 failed");return -3;}frame &#61; av_frame_alloc();if (!frame){return -4;}return 0;
}void CH264Decoder::unInitial()
{avcodec_close(context);av_free(context);av_frame_free(&frame);
}int CH264Decoder::decode(uint8_t *pDataIn, int nInSize, cv::Mat& res)
{
// av_init_packet(&packet);packet.size &#61; nInSize;packet.data &#61; pDataIn;if (packet.size > 0){int got_picture&#61;0;//int ret&#61; avcodec_decode_video2(context, frame, &got_picture, &packet);//新版用法int ret &#61; avcodec_send_packet(context, &packet);if (ret &#61;&#61; 0) got_picture &#61; avcodec_receive_frame(context, frame); //got_picture &#61; 0 success, a frame was returnedif (ret <0){printf("avcodec_encode_video2 failed");return -2;}if (got_picture&#61;&#61;0)//采用avcodec_decode_video2时,此处为if (got_picture){avframe_to_cvmat(frame,res);}}else{printf("no data to decode");return -1;}return 0;
}int CH264Decoder::avframe_to_cvmat(AVFrame *frame,cv::Mat& res)
{int width &#61; frame->width, height &#61; frame->height;res.create(height*3/2, width, CV_8UC1);memcpy( res.data, frame->data[0], width*height );memcpy( res.data &#43; width*height, frame->data[1], width*height/4 );memcpy( res.data &#43; width*height*5/4, frame->data[2], width*height/4 );//cv::imshow( "yuv_show", res );//yuv格式cv::cvtColor( res, res, cv::COLOR_YUV2BGR_I420 );//bgr格式//cv::imshow( "bgr_show", bgr );return 0;}
AVFrame * CH264Decoder::cvmat2avframe(cv::Mat mat) {// alloc avframeAVFrame *avframe &#61; av_frame_alloc();if (avframe && !mat.empty()) {avframe->format &#61; AV_PIX_FMT_YUV420P;avframe->width &#61; mat.cols;avframe->height &#61; mat.rows;av_frame_get_buffer(avframe, 0);av_frame_make_writable(avframe);cv::Mat yuv; // convert to yuv420p firstcv::cvtColor(mat, yuv, cv::COLOR_BGR2YUV_I420);// calc frame sizeint frame_size &#61; mat.cols * mat.rows;unsigned char *pdata &#61; yuv.data;// fill yuv420// yyy yyy yyy yyy// uuu// vvvavframe->data[0] &#61; pdata; // fill yavframe->data[1] &#61; pdata &#43; frame_size; // fill uavframe->data[2] &#61; pdata &#43; frame_size * 5 / 4; // fill v}return avframe;
}

编码&#43;解码示例

x264编码&#43;H264解码示例

X264EncoderDemo.cpp

//
// Created by liheng on 19-12-9.
//#include "x264_encoder.h"
#include "h264decoder.h"
#include
#include int main()
{cv::Mat frame;cv::VideoCapture videoCapture("/home/liheng/ADAS_Video/1120/ADAS_Video-20191120-151849.mp4");for (int i &#61; 0; i <10; &#43;&#43;i){videoCapture >> frame;}//x264 encodex264Encoder m_x264Encoder;m_x264Encoder.Create(1280,720,3,30);cv::Mat x264_dst;//h264 decodeCH264Decoder m_h264Decoder;m_h264Decoder.initial();//cv encodeint jpeg_quality &#61; 75;std::vector params;params.push_back(cv::IMWRITE_JPEG_QUALITY);params.push_back(jpeg_quality);cv::Mat cv_dst;int nWaitTime &#61;1;while (1){videoCapture >>frame;if( frame.empty() )break;cv::imshow("src",frame);cv::Mat _frame;cv::resize(frame,_frame,cv::Size(),0.5,0.5);//cv ecode &#43; cv decodedouble timePoint1 &#61; cv::getTickCount();std::vector jpgSize;cv::imencode(".jpg", _frame, jpgSize, params);cv_dst &#61; cv::imdecode(jpgSize,cv::IMREAD_COLOR);cv::imshow("cv_dst",cv_dst);//x264 ecode &#43; h264 decodedouble timePoint2 &#61; cv::getTickCount();int size &#61; m_x264Encoder.EncodeOneFrame(frame);uchar* data &#61; nullptr;data &#61; m_x264Encoder.GetEncodedFrame();m_h264Decoder.decode(data,size,x264_dst);cv::imshow("x264_dst",x264_dst);double timePoint3 &#61; cv::getTickCount();//cv::Mat diff &#61; x264_dst - frame;//cv::imshow("diff",diff);//查看编解码前后图像是否有差异printf("cv::encode size:%d Fps:%.2f, x264 encode size:%d,Fps:%.2f\n",jpgSize.size(),cv::getTickFrequency()/(timePoint2-timePoint1),size,cv::getTickFrequency()/(timePoint3-timePoint2));char chKey &#61; cv::waitKey(nWaitTime);//ESCif (27 &#61;&#61; chKey)break;else if (&#39; &#39; &#61;&#61; chKey) nWaitTime &#61; !nWaitTime;}return 0;
}

上面代码中对比了cv::encode和x264对Mat进行编码&#xff0c;在编码后数据量的大小&#xff0c;和视频质量两个方面的效果对比。从数据量上来看&#xff0c;cv::encode编码后数据量远大于x264编码数据量&#xff0c;即使采用75%的压缩率&#xff0c;cv::encode的数据量仍远高于x264&#xff0c;并且压缩后视频质量不如x264压缩后视频质量。

H264编码&#43;H264解码示例

H264EncoderDemo.cpp

//
// Created by liheng on 19-12-9.
//#include "h264encoder.h"
#include "h264decoder.h"
#include
#include int main()
{cv::Mat frame;cv::Mat dst;cv::VideoCapture videoCapture("/home/liheng/ADAS_Video/1120/ADAS_Video-20191120-151849.mp4");for (int i &#61; 0; i <10; &#43;&#43;i){videoCapture >> frame;}h264Encoder h264;AvH264EncConfig conf;conf.width &#61; 1280;conf.height &#61; 720;conf.gop_size &#61; 10;conf.max_b_frames &#61; 0;conf.frame_rate &#61; 30;h264.Init(conf);CH264Decoder m_h264Decoder;m_h264Decoder.initial();int jpeg_quality &#61; 75;std::vector params;params.push_back(cv::IMWRITE_JPEG_QUALITY);params.push_back(jpeg_quality);cv::Mat cvDst;int nWaitTime &#61;1;while (1){videoCapture >>frame;if( frame.empty() )break;cv::imshow("src",frame);cv::Mat _frame;cv::resize(frame,_frame,cv::Size(),0.5,0.5);double timePoint1 &#61; cv::getTickCount();std::vector jpgSize;cv::imencode(".jpg", _frame, jpgSize, params);double timePoint2 &#61; cv::getTickCount();cvDst &#61; cv::imdecode(jpgSize,cv::IMREAD_COLOR);cv::imshow("cvdecode",cvDst);// do encodeAVPacket *pkt &#61; h264.encode(frame);int size &#61; pkt->size;uchar* data &#61; nullptr;data &#61; pkt->data;m_h264Decoder.decode(data,size,dst);cv::imshow("decode",dst);double timePoint3 &#61; cv::getTickCount();//cv::Mat diff &#61; dst - frame;//cv::imshow("diff",diff);//查看编解码前后图像是否有差异printf("cv::encode size:%d Fps:%.2f, h264 encode size:%d,Fps:%.2f\n",jpgSize.size(),cv::getTickFrequency()/(timePoint2-timePoint1),size,cv::getTickFrequency()/(timePoint3-timePoint2));char chKey &#61; cv::waitKey(nWaitTime);//ESCif (27 &#61;&#61; chKey)break;else if (&#39; &#39; &#61;&#61; chKey) nWaitTime &#61; !nWaitTime;}return 0;
}

以上两个.cpp文件对应的CMakeLists.txt文件内容&#xff1a;
CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(H264Demo)set(CMAKE_CXX_STANDARD 11)if (CMAKE_BUILD_TYPE STREQUAL "")message(STATUS "CMAKE_BUILD_TYPE not defined, &#39;Release&#39; will be used")set(CMAKE_BUILD_TYPE "Release")
endif()find_package( OpenMP REQUIRED)
if(OPENMP_FOUND)message("OPENMP FOUND")set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()set(OpenCV_DIR /usr/local/opencv3.4.1/share/OpenCV)
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)message(STATUS "OPENCV found")
else (OpenCV_FOUND)message(WARNING "OPENCV is disabled or not found")return()
endif()add_executable(X264EncoderDemo X264EncoderDemo.cpp x264_encoder.cpp h264encoder.cpp h264decoder.cpp)
target_link_libraries(X264EncoderDemo ${OpenCV_LIBRARIES}x264avformat avdevice avcodec avutil avfilter postproc swresample swscale)add_executable(H264EncoderDemo H264EncoderDemo.cpp h264decoder.cpp h264encoder.cpp)
target_link_libraries(H264EncoderDemo ${OpenCV_LIBRARIES}avformat avdevice avcodec avutil avfilter postproc swresample swscale)

针对x264编码&#xff0c;需要安装libx264库&#xff0c;安装命令为:sudo apt install libx264-dev,H264编解码需要安装ffmpeg库&#xff0c;同样采用apt命令进行安装即可。


我在ADAS程序中将视频发送部分修改为采用x264进行编码后&#xff0c;能够在不缩放视频的情况下进行传输&#xff0c;效果满足使用要求&#xff0c;非常满意。不过&#xff0c;随后&#xff0c;我发现&#xff0c;利用gstreamer-rtsp-sever也能够实现同样的效果&#xff0c;该方式采用rtsp视频流的形式进行视频传输&#xff0c;在接收端&#xff0c;可以直接利用cv::VideoCapture进行视频接收&#xff0c;不用编写额外的解码代码&#xff0c;非常方便&#xff0c;此外&#xff0c;也可以利用VLC media 进行视频接收&#xff0c;此时甚至不用专门编写视频接收代码了&#xff1b;建议有需求的可以尝试一下该方法&#xff0c;代码也是非常简单&#xff0c;此处就不贴出了&#xff08;主要是感觉我的这个代码并未写完善&#xff0c;有缺陷&#xff09;。



下面的是我的公众号二维码图片&#xff0c;欢迎关注。
图注:幼儿园的学霸


推荐阅读
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • HTML 页面中调用 JavaScript 函数生成随机数值并自动展示
    在HTML页面中,通过调用JavaScript函数生成随机数值,并将其自动展示在页面上。具体实现包括构建HTML页面结构,定义JavaScript函数以生成随机数,以及在页面加载时自动调用该函数并将结果呈现给用户。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在C++程序中,文档A的每一行包含一个结构体数据,其中某些字段可能包含不同数量的数字。需要将这些结构体数据逐行读取并存储到向量中,随后不仅在控制台上显示,还要输出到新创建的文档B中。希望得到指导,感谢! ... [详细]
  • SIoU Loss 的原理详解及代码实现分析
    本文详细解析了 SIoU Loss 的原理及其在边界框回归任务中的优势,并通过代码实现对其性能进行了深入分析。SIoU Loss 作为一种改进的损失函数,能够更有效地优化目标检测模型的边界框回归效果,提升模型的准确性和鲁棒性。文中还提供了具体的代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • QT框架中事件循环机制及事件分发类详解
    在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。 ... [详细]
  • 在关系型数据库中,数据约束是指在向数据表中插入数据时必须遵循的限制条件。在MySQL和MariaDB中,常见的数据约束包括主键约束、唯一键约束、外键约束以及非空约束等。这些约束确保了数据的完整性和一致性,是数据库管理中的重要组成部分。通过合理设置和使用这些约束,可以有效防止数据冗余和错误,提升数据库的可靠性和性能。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 在本文中,我们将为 HelloWorld 项目添加视图组件,以确保控制器返回的视图路径能够正确映射到指定页面。这一步骤将为后续的测试和开发奠定基础。首先,我们将介绍如何配置视图解析器,以便 SpringMVC 能够识别并渲染相应的视图文件。 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • 微信平台通过盛派SDK(sdk.weixin.senparc.com)允许服务号和订阅号使用appId和token读取关注用户的个人信息。然而,这一过程需严格遵守隐私保护和数据安全的相关规定,确保用户数据的安全性和隐私性。 ... [详细]
author-avatar
沈婧颖_491
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有