fileapi::WriteFile() doesn't send an input, if processthreadsapi::STARTUPINFO::hStdError is set (ffmpeg)

Viewed 49

I'm trying to capture my screen using ffmpeg in a different thread (which I create using processthreadsapi::CreateProcess()) so I'd be able to do something else in the main thread, and redirect ffmpeg output, so it wouldn't pop up in the console for the user to see. To stop filming, I send a 'q' input using WriteFile(), and after that I want to save ffmpeg accumulated output using ReadFile().

However, if I set STARTUPINFO::hStdError (note, that ffmpeg output goes to stderr) to a pipe, from which I could read the accumulated data, the inputs I send using WriteFile() are no longer registered and ffmpeg.exe keeps running.

I've tried redirecting ffmpeg output in a simple command line, but I can still stop the process by pressing the q button.

Also, if I record for less than 8 seconds, the input is registered and ffmpeg.exe closes.

Is there something wrong with my code, or is it processthreadsapi issue, any hints will be kindly appreciared!

Here's a minimal code of how I am trying to do it:


#include <iostream>

#include <conio.h>
#include <windows.h>

using namespace std;

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

int main()
{
    //Create IN and OUT pipes
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.lpSecurityDescriptor = NULL;


    if (! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
        cout<<"StdoutRd CreatePipe error"<<endl;

    if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0) )
        cout<<"Stdin CreatePipe error"<<endl;


   PROCESS_INFORMATION piProcInfo;
   STARTUPINFO siStartInfo;

   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );

   siStartInfo.cb = sizeof(STARTUPINFO);
   siStartInfo.hStdError = g_hChildStd_OUT_Wr;
   siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
   siStartInfo.hStdInput = g_hChildStd_IN_Rd;
   siStartInfo.dwFlags |= STARTF_USESTDHANDLES;


   //Start recording
   if(!CreateProcess(NULL,
      "ffmpeg -y -f gdigrab -framerate 2 -i desktop record.avi",     // command line
      NULL,          // process security attributes
      NULL,          // primary thread security attributes
      TRUE,          // handles are inherited
      0,             // creation flags
      NULL,          // use parent's environment
      NULL,          // use parent's current directory
      &siStartInfo,  // STARTUPINFO pointer
      &piProcInfo))  // receives PROCESS_INFORMATION
   {
    cout<<"Error create process"<<endl;
   }
   else
   {
       cout<<"Process created successfully"<<endl;
       cout<<"Press k to stop recording"<<endl;
   }

    //Record for a while
    while(getch() != 'k'){
        cout<<"While press k"<<endl;
    };

   cout<<"Stop recording called"<<endl;

    //Stop recording by emulating a Q button push
    DWORD dwWritten;
    CHAR chBufW[1] = {'q'};

    if ( ! WriteFile(g_hChildStd_IN_Wr, chBufW, 1, &dwWritten, NULL) )
        cout<<"Error write file"<<endl;

    //Save stdError (ffmpeg) data
    DWORD dwRead;
    char stdErrorData[4096];
    bool bSuccess;

    bSuccess = ReadFile( g_hChildStd_OUT_Wr, stdErrorData, 4096, &dwRead, NULL);

    if(!bSuccess || dwRead == 0)
        cout<<"Read failed"<<endl;
    else{
        cout<<"Read success"<<endl;
    }

    cout<<"Press to exit"<<endl;
    while(getch() != 'k');
    return 0;
}

1 Answers

To answer my own question, the issue was that when the handle pipe, where the ffmpeg output is going to, fills up, it stops the ffmpeg process, until I'd clear some space for new text to come in. This is happening, because ffmpeg continiously outputs recording info.

I hope this will be useful for someone :)

Related