昆明网站建设加q.479185700,酒店加盟什么网站建设,孟州网站开发app,电影网站带采集FFMPEGQt 实时显示本机USB摄像头1080p画面以及同步录制mp4视频 文章目录 FFMPEGQt 实时显示本机USB摄像头1080p画面以及同步录制mp4视频1、前言1.1 目标1.2 一些说明 2、效果3、代码3.1 思路3.2 工程目录3.3 核心代码 4、全部代码获取 1、前言 本文通过FFMPEG(7.0.2)与Qt(5.13.…FFMPEGQt 实时显示本机USB摄像头1080p画面以及同步录制mp4视频 文章目录 FFMPEGQt 实时显示本机USB摄像头1080p画面以及同步录制mp4视频1、前言1.1 目标1.2 一些说明 2、效果3、代码3.1 思路3.2 工程目录3.3 核心代码 4、全部代码获取 1、前言 本文通过FFMPEG(7.0.2)与Qt(5.13.2)实现在windows10系统下实时预览以及录制1080p视频。 本文程序只对视频数据进行处理不考虑音频数据。
1.1 目标 在win10平台用FFMPEG和Qt实现实时显示USB摄像头画面以及同步录制mp4视频。
1.2 一些说明 本程序实现USB摄像头数据视频流获取及显示录制、显示的视频质量与USB相机有关本人摄像头为1920*108030Hz。 USB相机默认视频流格式会有差别如果需要特定格式及分辨率的时候需要手动设置。 大部分USB摄像头有MJPG和YUV两种格式为了追求高分辨率可以将摄像头参数设置为MJPG输入。需要通过以下代码实现。即配置AVDictionary。需要同时配置相机的帧率、分辨率和格式不能只设置输入格式要不然不成功。
AVDictionary* options NULL;
av_dict_set(options, input_format, mjpeg, 0);
av_dict_set(options, framerate, 30, 0);
av_dict_set(options, video_size, 1920x1080, 0);avformat_open_input(pFormatCtx_, in_file.c_str(), ifmt, options);2、效果 先看演示效果视频 FFMPEGQt win10 实时预览录制1080p视频 3、代码 本项目全部代码请到此处获取https://download.csdn.net/download/wang_chao118/89921908
3.1 思路 通过Qt进行画面可视化FFMPEG对USB视频流进行解码、编码以及存储。将FFMPEG的循环操作放到一个子线程中与现实线程隔离。 通过Qt的信号槽机制将FFMPEG循环操作过程中解码出的单帧图像转化成QImage*通过信号传递至主线程进行图像绘制。
thread_ new std::thread(CameraThread::Run, this);QObject::connect(camera_thread_, CameraThread::frameReady, w, Widget::updatePic);3.2 工程目录 本项目中将FFMPEG相关上下文的初始化、解码、编码、记录循环功能集成在一个CameraThread类中。 CameraThread类继承Thread类。Thread类中实现子线程的初始化、开始、停止、运行等基础功能。
3.3 核心代码 CameraThread::Start()函数用于初始化FFMPEG的各类上下文设置解码器、编码器参数等在Qt界面中只要点击“开始录制”按钮就会调用该函数点击“停止录制”按钮调用CameraThread::Stop()函数对上下文进行清理。
int CameraThread::Start()
{start_pts 0;int ret 0;/******************************************打开摄像头设备********************************************/const AVInputFormat* m_inputFormat av_find_input_format(dshow);inputContext avformat_alloc_context();AVDictionary *options nullptr;ret avformat_open_input(inputContext, url_.c_str(), m_inputFormat, options);if (ret 0){qDebug()avformat_open_input failed, ret: ret;return -1;}// 获取摄像头流信息ret avformat_find_stream_info(inputContext, nullptr);if (ret 0){qDebug()Could not retrieve input stream information;return -1;}int videoStreamId -1;videoStreamId av_find_best_stream(inputContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);inputStream inputContext-streams[videoStreamId];codecParameters inputStream-codecpar;// 获取摄像头的实际分辨率和帧率int actual_width codecParameters-width;int actual_height codecParameters-height;AVRational actual_frame_rate inputStream-r_frame_rate;qDebug() Camera Resolution: actual_width x actual_height;qDebug() Camera Frame Rate: actual_frame_rate.num / actual_frame_rate.den fps;/******************************************创建解码器********************************************/// 查找解码器auto codec_id inputStream-codecpar-codec_id;const AVCodec* decoder avcodec_find_decoder(codec_id);if (!decoder) {qDebug()Unsupported codec !;return -1;}// 创建解码器上下文decoderContext avcodec_alloc_context3(decoder);ret avcodec_parameters_to_context(decoderContext, codecParameters);if (ret0) {qDebug()Failed to copy codec parameters to decoder context.;return -1;}qDebug() output pix_fmt av_get_pix_fmt_name((AVPixelFormat)codecParameters-format) codecParameters-format;ret avcodec_open2(decoderContext, decoder, nullptr);if (ret0) {qDebug()Failed to open decoder.;return -1;}/******************************************创建编码器********************************************/// 查找 H.264 编码器const AVCodec* pEncoderH264 avcodec_find_encoder(AV_CODEC_ID_H264);if (pEncoderH264 NULL) {qDebug() Unsupported encodec.;return -1;}//视频编码器上下文encoderContext avcodec_alloc_context3(pEncoderH264);encoderContext-time_base.num inputStream-time_base.num;encoderContext-time_base.den inputStream-time_base.den;encoderContext-has_b_frames 0;
// encoderContext-gop_size 50;encoderContext-codec_id pEncoderH264-id;encoderContext-pix_fmt (AVPixelFormat)inputStream-codecpar-format;qDebug()111111111111111111111111111111: encoderContext-pix_fmt;encoderContext-width inputStream-codecpar-width;encoderContext-height inputStream-codecpar-height;
// encoderContext-bit_rate 0;encoderContext-flags | AV_CODEC_FLAG_GLOBAL_HEADER;encoderContext-framerate inputStream-avg_frame_rate;//编码帧率按照采集帧率来
// encoderContext-bit_rate 5000000; //数值越小文件越小//编码器不用等待缓冲区填满接收到数据即开始编码av_opt_set(encoderContext-priv_data, tune, zerolatency, 0);
// av_opt_set(encoderContext-priv_data, crf, 23, 0); //数值越大越模糊存储文件越小qDebug() encoder h246 information:;qDebug() encode fps (encoderContext-framerate.num / encoderContext-framerate.den) ;qDebug() w encoderContext-width , h encoderContext-height;qDebug() input pix format av_get_pix_fmt_name(encoderContext-pix_fmt) encoderContext-pix_fmt ;ret avcodec_open2(encoderContext, pEncoderH264, NULL);if (ret 0) {qDebug() avcodec_open2;return -1;}/******************************************创建视频输出文件********************************************/const AVOutputFormat* outputFormat av_guess_format(mp4, NULL, NULL);outputContext avformat_alloc_context();outputContext-oformat const_castAVOutputFormat*(outputFormat);// 创建输出流outputStream avformat_new_stream(outputContext, encoderContext-codec);if (!outputStream){qDebug() Failed to create output stream;return -1;}avcodec_parameters_from_context(outputStream-codecpar, encoderContext);outputStream-time_base av_inv_q(inputStream-r_frame_rate);// 创建输出 MP4 文件mp4_count;m_mp4_file_name m_mp4_file_name_header std::to_string(mp4_count) .mp4;ret avio_open(outputContext-pb, m_mp4_file_name.c_str(), AVIO_FLAG_WRITE);if(ret 0){qDebug() Failed to create output file.;return -1;}ret avformat_write_header(outputContext, NULL);if(ret 0){qDebug() Failed to write header;return -1;}/******************************************开线程****************************************************/thread_ new std::thread(CameraThread::Run, this);if (!thread_){qDebug()new std::thread(CameraThread::Run, this) failed;return -1;}return 0;
} CameraThread::Run()函数是循环录制过程的执行函数主要是从FFMPEG上下文中取出视频数据包AVPacket解码至视频帧AVFrame再按相应格式H264编码成AVPacket然后再保存至文件中。
void CameraThread::Run()
{qDebug() Run into CameraThread::Run()!;int ret 0;SwsContext *sws_ctx nullptr;while (!abort_){// 读取视频帧ret av_read_frame(inputContext, captured_packet);if (ret 0){qDebug() av_read_frame error;continue; // 如果读取失败跳过到下一帧}// start capture pts from 0// 初始化 start_ptsif (start_pts 0){start_pts captured_packet-pts; // 仅在第一次读取时设置}captured_packet-pts - start_pts;qDebug()captured_packet-pts: captured_packet-pts;av_log(nullptr, AV_LOG_INFO, packet size is %d\n, captured_packet-size);// 解码 MJPEG 数据ret avcodec_send_packet(decoderContext, captured_packet);if (ret 0){qDebug() Error sending packet for decoding.;av_packet_unref(captured_packet); // 释放 packet 内存continue; // 继续读取下一个包}auto decoded_frame av_frame_alloc();ret avcodec_receive_frame(decoderContext, decoded_frame); // decoded_frame 自带引用计数if (ret AVERROR(EAGAIN) || ret AVERROR_EOF){av_frame_free(decoded_frame); // 确保在这些情况下也释放内存av_packet_unref(captured_packet); // 释放 packet 内存continue;}else if (ret 0){qDebug() avcodec_receive_frame failed!;av_frame_free(decoded_frame);av_packet_unref(captured_packet); // 释放 packet 内存break;}// 编码 H264 数据ret avcodec_send_frame(encoderContext, decoded_frame);if (ret 0){qDebug() Error sending frame for encoding.;av_frame_free(decoded_frame);av_packet_unref(captured_packet); // 释放 packet 内存continue;}/******************************************发送QImage***********************************************/// 转换解码后的帧为 QImageif (!sws_ctx){sws_ctx sws_getContext(decoded_frame-width, decoded_frame-height,(AVPixelFormat)decoded_frame-format,decoded_frame-width, decoded_frame-height,AV_PIX_FMT_RGB32, SWS_BILINEAR, nullptr, nullptr, nullptr);}QImage image(decoded_frame-width, decoded_frame-height, QImage::Format_RGB32);uint8_t *dst[4] { image.bits(), nullptr, nullptr, nullptr };int dstStride[4] { image.bytesPerLine(), 0, 0, 0 };sws_scale(sws_ctx, decoded_frame-data, decoded_frame-linesize, 0,decoded_frame-height, dst, dstStride);// 发射信号emit frameReady(image);/******************************************存视频****************************************************/ret avcodec_receive_packet(encoderContext, h264_pkt);if (ret 0){qDebug() avcodec_receive_packet error.;av_frame_free(decoded_frame);av_packet_unref(captured_packet); // 释放 packet 内存continue;}ret av_write_frame(outputContext, h264_pkt);if (ret 0){qDebug() write error.;}// 释放 decoded_frame 和 packet 内存av_frame_free(decoded_frame);av_packet_unref(captured_packet); // 释放 packet 内存}
}4、全部代码获取 本项目全部代码请到此处获取https://download.csdn.net/download/wang_chao118/89921908