-1

I am trying to record my desktop screen and save it into a video using opencv videoWriter but always end up having a 6kb video which is not even playable.

Here is my code for the same, I'm first creating mat object for the screen and then writing them into the file.

#include "pch.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> 
#include <iostream>
#include <stdio.h>
#include <opencv2/objdetect/objdetect.hpp>
#include <Windows.h>

using namespace std;
using namespace cv;


int height;
int width;

Mat hwnd2mat()
{
  // returning Mat object for screen and working fine as I'm showing it into a window
}


void CaptureScreen()
{
    int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    HWND hDesktopWnd = GetDesktopWindow();
    int key = 0;
    string filename = "D:/outcpp.avi";
    cv::Size targetSize = cv::Size(320, 240);
    VideoWriter video(filename, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 10, targetSize);
    while (1)
    {
        Mat frame = hwnd2mat();

        cv::Mat image = frame;
        cv::Mat dst;
        cv::resize(image, dst, targetSize);

        if (dst.empty())
            break;
        video.write(dst);
        imshow("Frame", dst);
        char c = (char)waitKey(1);
        if (c == 27)
            break;
    }
    video.release();
    destroyAllWindows();
    //readVideo(filename);
}




int main(int argc, char **argv)
{
    CaptureScreen();
    return 0;
}
Matthew Walton
  • 9,809
  • 3
  • 27
  • 36
josh
  • 79
  • 12

2 Answers2

1

You are calling a function that, according to its signature, returns something, but actually doesn't. This causes undefined behaviour according to the C++ standard, so your program is buggy.

Please also enable warnings, because the compiler would normally have told you exactly that.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
  • are you talking about `Mat hwnd2mat()` ? – josh Dec 31 '18 at 08:22
  • That's a rather cryptic answer! – Mark Setchell Dec 31 '18 at 10:50
  • I agree, @MarkSetchell. Maybe the answer could have been a comment, too. I also don't claim that the answer fixes all problems with above code or that the behaviour changes, but at least it fixes one bug in the code. – Ulrich Eckhardt Dec 31 '18 at 11:24
  • `hwnd2mat()`, of course. `main()` is the only exception, it's allowed to not return anything from it, despite the `int` return type declaration. – Ulrich Eckhardt Dec 31 '18 at 12:15
  • @UlrichEckhardt i used that function directly from [here](https://stackoverflow.com/a/36696070) – josh Jan 02 '19 at 08:35
  • Hold on: You say that the code you provided is not wat you are actually running? In that case, you don't have a [mcve] and your question is thus considered off-topic. – Ulrich Eckhardt Jan 02 '19 at 18:55
0

Try different fourcc code with *.mp4, which is better anyway, and run without showing the image. Make sure video is opened and released successfully.

void hwnd2mat(cv::Mat &mat)
{
    int w = mat.cols;
    int h = mat.rows;

    auto hdc = GetDC(0);
    auto memdc = CreateCompatibleDC(hdc);
    auto hbitmap = CreateCompatibleBitmap(hdc, w, h);
    auto holdbmp = SelectObject(memdc, hbitmap);
    BitBlt(memdc, 0, 0, w, h, hdc, 0, 0, SRCCOPY);

    BITMAPINFOHEADER bi = { sizeof(bi), w, -h, 1, 24 };
    GetDIBits(hdc, hbitmap, 0, h, mat.data, (BITMAPINFO*)&bi, 0);

    SelectObject(memdc, holdbmp);
    DeleteDC(memdc);
    DeleteObject(hbitmap);
    ReleaseDC(0, hdc);
}

int main()
{
    int w = GetSystemMetrics(SM_CXSCREEN);
    int h = GetSystemMetrics(SM_CYSCREEN);
    cv::Size size = cv::Size(w, h);
    Mat frame(size, CV_8UC3);

    double fps = 10.0;

    //string filename = "d:\\outcpp.avi";
    //auto fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G');

    string filename = "d:\\outcpp.mp4";
    auto fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');

    VideoWriter video(filename, fourcc, fps, frame.size());
    if(!video.isOpened())
    {
        cout << "codec failed\n";
        return 0;
    }

    while(GetAsyncKeyState(VK_ESCAPE) == 0)
    {
        cout << ".";
        hwnd2mat(frame);
        video.write(frame);
        Sleep(int(1000.0/fps));
    }

    video.release();
    cout << "\nreleased\n";

    return 0;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • @barnak i tried your code but it keep exiting on `if(!video.isOpened()) { cout << "codec failed\n"; return 0; }` so i comment it out, after that it not creating any mp4 video and on `imshow(frame)` its showing grey window. – josh Jan 05 '19 at 16:38
  • You don't have that codec installed on your computer, try a different codec (make sure it matches the file extension). If `video.isOpend()` has failed then don't continue. – Barmak Shemirani Jan 05 '19 at 16:47
  • @barnak i tried again and just changed my filepath, after that its creating video in mp4 but in video its showing screen in bended way. any idea why ? – josh Jan 05 '19 at 17:42
  • @barnak thanks for your help,its working fine now , i just changed `int w = GetSystemMetrics(SM_CXSCREEN)+10;` in your code and idky its working and what was the bug here. – josh Jan 05 '19 at 18:59