ffmpeg 屏幕抓取

news/2024/11/13 3:47:45/

1、在Windows系统使用libavdevice抓取屏幕数据有两种方法:gdigrab和dshow。

(1)、使用dshow进行屏幕抓取首先要安装:screen capture recorder,下载地址:https://sourceforge.net/projects/screencapturer/files/

我的电脑是win10家庭中文版,使用dshow进行屏幕抓取时失败,报错如下:

if(nullptr == (pInFmt = const_cast<AVInputFormat*>(av_find_input_format("dshow")))){qDebug() << "find AVInputFormat failed." << endl;break;}//打开输入设备if(avformat_open_input(&pFmtCtx, "video=screen-capture-recorder", pInFmt, nullptr) != 0){qDebug() << "avformat_open_input failed." << endl;break;}

 音频可以获取成功,一直也没有找到问题原因,我看别人博客貌似都可以成功!

(2)使用dgigrab可以进行屏幕抓取成功:

if(nullptr == (pInFmt = const_cast<AVInputFormat*>(av_find_input_format("gdigrab")))){qDebug() << "find AVInputFormat failed." << endl;break;}AVDictionary* options = NULL;//Set some options://1、grabbing frame rate//av_dict_set(&options,"framerate","5",0);//2、The distance from the left edge of the screen or desktop//av_dict_set(&options,"offset_x","20",0);//3、The distance from the top edge of the screen or desktop//av_dict_set(&options,"offset_y","40",0);//4、Video frame size. The default is to capture the full screen//av_dict_set(&options,"video_size","640x480",0);//打开输入设备if(avformat_open_input(&pFmtCtx, "desktop", pInFmt, &options) < 0){qDebug() << "avformat_open_input failed." << endl;break;}

2、主要实现代码:

(1)、屏幕抓取操作放在单独线程中执行:

signals://发送抓取的图像帧void sig_sendQImage(QImage);public slots://抓取操作void slot_slog_screenRecord();

void videoThread::slog_screenRecord()
{AVFormatContext* pFmtCtx = nullptr;AVInputFormat*   pInFmt  = nullptr;int nVideoIndex          = -1;AVCodecParameters* pCodecParam = nullptr;AVCodecContext   * pCodecCtx   = nullptr;AVCodec          * pCodec    = nullptr;AVFrame* pFrame    = av_frame_alloc();AVFrame* pFrameRGB = av_frame_alloc();AVPacket* pkt = nullptr;do{//注册组件:libavdeviceavdevice_register_all();avformat_network_init();//创建设备上下文if(nullptr == (pFmtCtx = avformat_alloc_context())){qDebug() << "create AVFormatContext failed." << endl;break;}//查找摄像头设备//1.gdigrab//2.dshow:if(0)//dshow{if(nullptr == (pInFmt = const_cast<AVInputFormat*>(av_find_input_format("dshow")))){qDebug() << "find AVInputFormat failed." << endl;break;}QList<QCameraInfo> cameras = QCameraInfo::availableCameras();QString urlString = QString("video=") + cameras.at(1).description();//打开输入设备if(avformat_open_input(&pFmtCtx, "video=screen-capture-recorder", pInFmt, nullptr) != 0){qDebug() << "avformat_open_input failed." << endl;break;}}else //vfwcap{if(nullptr == (pInFmt = const_cast<AVInputFormat*>(av_find_input_format("gdigrab")))){qDebug() << "find AVInputFormat failed." << endl;break;}AVDictionary* options = NULL;//Set some options://1、grabbing frame rate//av_dict_set(&options,"framerate","5",0);//2、The distance from the left edge of the screen or desktop//av_dict_set(&options,"offset_x","20",0);//3、The distance from the top edge of the screen or desktop//av_dict_set(&options,"offset_y","40",0);//4、Video frame size. The default is to capture the full screen//av_dict_set(&options,"video_size","640x480",0);//打开输入设备if(avformat_open_input(&pFmtCtx, "desktop", pInFmt, &options) < 0){qDebug() << "avformat_open_input failed." << endl;break;}}//查找流信息if(avformat_find_stream_info(pFmtCtx, NULL) < 0){qDebug() << "cannot find stream info." << endl;break;}for(size_t i = 0;i < pFmtCtx->nb_streams;i++){if(pFmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){nVideoIndex = i;break;}}if(nVideoIndex == -1){qDebug() << "cannot find video stream." << endl;break;}//查找编码器pCodecParam = pFmtCtx->streams[nVideoIndex]->codecpar;if(nullptr == (pCodec = const_cast<AVCodec*>(avcodec_find_decoder(pCodecParam->codec_id)))){qDebug() << "cannot find codec." << endl;break;}//创建编码器上下文if(nullptr == (pCodecCtx = avcodec_alloc_context3(pCodec))){qDebug() << "cannot alloc codecContext." << endl;break;}if(avcodec_parameters_to_context(pCodecCtx, pCodecParam) < 0){qDebug() << "cannot initialize codecContext." << endl;break;}//打开编码器if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0){qDebug() << "cannot open codec." << endl;break;}//设置帧数据转换上下文struct SwsContext *img_convert_ctx = nullptr;img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24,SWS_BICUBIC, NULL, NULL, NULL);qDebug() << pCodecCtx->width << "---" << pCodecCtx->height << endl;int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1);uint8_t* out_buffer = (unsigned char*)av_malloc(static_cast<unsigned long long>(numBytes) * sizeof(unsigned char));//绑定内存块if(av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize,out_buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1) < 0){qDebug() << "av_image_fill_arrays failed." << endl;break;}int ret;pkt = av_packet_alloc();av_new_packet(pkt, pCodecCtx->width * pCodecCtx->height);while(av_read_frame(pFmtCtx, pkt) >= 0){if(pkt->stream_index == nVideoIndex){if(avcodec_send_packet(pCodecCtx, pkt)>=0){while((ret = avcodec_receive_frame(pCodecCtx, pFrame)) >= 0){if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)return;else if (ret < 0) {return;}//将解码后数据转换为Rgb格式数据sws_scale(img_convert_ctx,pFrame->data, pFrame->linesize,0, pCodecCtx->height,pFrameRGB->data, pFrameRGB->linesize);//将img发送给界面进行显示QImage img(out_buffer, pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB888);emit sig_sendQImage(img);QThread::msleep(50);}}av_packet_unref(pkt);}}}while(0);av_packet_free(&pkt);avcodec_close(pCodecCtx);avcodec_parameters_free(&pCodecParam);av_frame_free(&pFrame);av_frame_free(&pFrameRGB);if(pFmtCtx){avformat_close_input(&pFmtCtx);avformat_free_context(pFmtCtx);}
}

 (1)、线程的创建,信号槽的绑定等操作:

void MainWindow::createWorkThread()
{videoThread* pVideoThread = new videoThread;pVideoThread->moveToThread(&m_workThread);//线程结束后销毁videoThread对象connect(&m_workThread, &QThread::finished, pVideoThread, &QObject::deleteLater);//绑定相关信号槽connect(this, &MainWindow::sig_screenRecord, pVideoThread, &videoThread::slog_screenRecord);connect(pVideoThread, &videoThread::sig_sendQImage, this, &MainWindow::slot_displayImage);m_workThread.start();}void MainWindow::releaseWorkThread()
{m_workThread.quit();m_workThread.wait();
}void MainWindow::slot_displayImage(QImage img)
{ui->labDisplay->setPixmap(QPixmap::fromImage(img).scaled(ui->labDisplay->width(), ui->labDisplay->height()));
}void MainWindow::on_btnPlay_clicked()
{emit sig_screenRecord();
}

(3)、抓取效果:


http://www.ppmy.cn/news/506123.html

相关文章

c++ 抓取桌面屏幕并转为jpg图片

抓取屏幕代码 char* getScreen(unsigned long &jpg_size){ HWND DeskWnd::GetDesktopWindow();//获取桌面窗口句柄RECT DeskRC;::GetClientRect(DeskWnd,&DeskRC);//获取窗口大小HDC DeskDCGetDC(DeskWnd);//获取窗口DCHBITMAP DeskBmp::CreateCompatibleBitmap(DeskD…

利用Windows自带gdi32.dll实现抓取屏幕

internal static void GetScreenShot( ) { //获得当前屏幕的大小 Rectangle rect new Rectangle(); rect Screen.AllScreens[0].WorkingArea; //计算图片的大小&#xff0c;因为图片的长和宽有可能超过目前屏幕的大小 //创建一个以当前屏幕为模板的图象 Control ctl new …

android实时抓取屏幕文字,Android录制屏幕的实现方法

原文:Paul Kinlan 翻译:Agora.io 长久以来,我一直希望能够直接从Android屏幕上进行录制并将其编码为多种格式,以便将录制内容嵌入在任意位置,而不需要安装任何软件。 如今,我们已经接近这个目标。Chrome团队正在添加一种功能,可以通过getUserMedia从Android设备上共享屏…

java获取屏幕截图

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; java教程全解 java获取屏幕截图 测试代码 public static void main(String[] args) {//文件与BufferedImage间的转换BufferedImage biigetScreen();img2file(bii,"jpg","test1.jpg"); …

捕获计算机屏幕++方法,在Win10中获取屏幕截图的五大方法

如果您是Win10的新手,或者甚至是专业人士在Win10中截取屏幕截图与其他操作系统相比有些困难。屏幕截图在某些情况下可以节省您的时间。此外,如果您指定截屏的所有不同方式,尤其是在Win10中,您绝对可以节省更多时间。请注意,所有这些截图都只适用于Win10,它可能适用于其他…

C++ 屏幕抓取代码及解析

代码 // An highlighted block void GetScreenShot(void) {BITMAPFILEHEADER bfHeader;BITMAPINFOHEADER biHeader;BITMAPINFO bInfo;HGDIOBJ hTempBitmap;HBITMAP hBitmap;BITMAP bAllDesktops;HDC hDC, hMemDC;LONG lWidth, lHeight;BYTE *bBits NULL;HANDLE hHeap GetPro…

C#实现捕获当前屏幕截图(转)

C#实现捕获当前屏幕截图(转) 编程思路&#xff08;API 编程&#xff09;&#xff1a;先调用 GetForegroundWindow 获取当前活动程序窗口句柄&#xff0c;然后调用 GetWindowDC 获取窗口的设备句柄&#xff08;或 GetDC 函数&#xff09;&#xff0c;调用 BitBlt 位图传输函数将…

python如何屏幕截图_Python实现屏幕截图的两种方式

使用windows API 使用PIL中的ImageGrab模块 下面对两者的特点和用法进行详细解释。 一、Python调用windows API实现屏幕截图 好处是 灵活 速度快 缺点是: 写法繁琐 不跨平台 import time import win32gui, win32ui, win32con, win32api def window_capture(filename): hwnd = …