Showing posts with label windows 8. Show all posts
Showing posts with label windows 8. Show all posts

Wednesday, June 1, 2016

Simple Screen Capture in Windows using FFmpeg

 One day, I want to record my FL Studio activity. I can't use FRAPS because I use Windows 8 where capturing Aero Desktop option in FRAPS is useless. I also tried CamStudio but it lags alot. I remembered that I have FFmpeg installed and use that for screen recording instead.

FFmpeg is a command-line application that focus mostly on audio and video related. Although it can be used to re-encode video to another format and it's bit complex, using it for screen recording is actually simple.

Before proceed, here are things you need
  • FFmpeg. Can be downloaded here
  • Stereo Mix audio input enabled in the audio devices (optional, only needed if you want to capture the audio also)
Now, extract the FFmpeg somewhere and double-click "ff-prompt.bat". It will add "ffmpeg" to the command prompt for the current CMD window. Now we can start recording.

To record specific window, the input will be title="<the window name>". To record the entire desktop, the input will be desktop.
Now to start recording, just type ffmpeg -f gdigrab -i <the input> capture.mkv and to stop recording, just press Ctrl+C in the CMD Window. The captured screen will be stored in "capture.mkv" file.

If you have stereo mix audio input, you can also record the audio. First we need to get the exact name of the stereo mix input name. Type ffmpeg -list_devices true -f dshow -i dummy 2>&1 | findstr /I "stereo mix". If there's no output, that means you don't have stereo mix. In my laptop, it output something like this

D:\pvid>ffmpeg -list_devices true -f dshow -i dummy 2>&1 | findstr /I "stereo mix"
[dshow @ 0000000001cbd040]  "Stereo Mix (Realtek High Definition Audio)"


"Stereo Mix (Realtek High Definition Audio)" is example of the actual stereo mix input name, at least in my laptop.

Now to record the audio+video, type ffmpeg -f dshow -i audio="<stereo mix name>" -f gdigrab -i <the input> capture.mkv

If you feel that your PC lags alot when capturing the screen or want to capture without losing any quality, you may want to capture the video (and audio if you capture it too) in uncompressed format first, then re-encode it later. FFmpeg also can be used to re-encode the video if you know how.

To record the uncompressed video only, type ffmpeg -f gdigrab -i <the input> -c:v libx264 -qp 0 -preset ultrafast capture.mkv. The size of the video might be large, but not as large as fraps.
For the audio+video, type ffmpeg -f dshow -i audio="<stereo mix name" -c:a pcm_s6le -f gdigrab -i <the input> -c:v libx264 -qp 0 -preset ultrafast capture.mkv

If possible, try to capture specific window only instead of the whole desktop. Capturing the whole desktop only gives framerate of 30FPS, while capturing specific window gives framerate 60FPS. It doesn't matter if the window size is small or big when capturing specific window, it will gives 60 FPS instead of the whole desktop which gives 30 FPS.

Friday, January 2, 2015

Run Windows 8 Metro Application from Desktop Application

After failed to create Rainmeter plugin which launch windows 8 application, i decide to make an application which launch windows 8 application from console application.

File: IApplicationAcitvationManager.h (For GCC/G++ Compiler)
// IApplicationActivationManager for MinGW
#pragma once
#ifdef _MSC_VER
#error "Not for Microsoft Compiler!"
#endif
#ifndef _SHLOBJIDL_H 
#include <shobjidl.h>
#endif
 
#ifdef __cplusplus
extern "C" {
#endif
const IID IID_IApplicationActivationManager={0x2e941141,0x7f97,0x4756,{0xba,0x1d,0x9d,0xec,0xde,0x89,0x4a,0x3d}};  // Visual Studio 2012 ShObjIdl.h:9159
const CLSID CLSID_ApplicationActivationManager={0x45BA127D,0x10A8,0x46EA,{0x8A,0xB7,0x56,0xEA,0x90,0x78,0x94,0x3C}}; // Visual Studio 2012 ShObjIdl.h:9399
 
typedef enum ACTIVATEOPTIONS {
 AO_NONE=0,
 AO_DESIGNMODE=1,
 AO_NOERRORUI=2,
 AO_NOSPLASHSCREEN=4
} ACTIVATEOPTIONS;
 
#define INTERFACE IApplicationActivationManager
DECLARE_INTERFACE_(IApplicationActivationManager,IUnknown) {
 STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 STDMETHOD_(ULONG,Release)(THIS) PURE;
 // Activates the specified Windows Store app for the generic launch contract (Windows.Launch) in the current session.
 STDMETHOD(ActivateApplication)(THIS_ const wchar_t*,const wchar_t*,ACTIVATEOPTIONS,unsigned long*) PURE;
 // Activates the specified Windows Store app for the file contract (Windows.File).
 // IShellItem doesn't exist. Replace with LPVOID
 STDMETHOD(ActivateForFile)(THIS_ const wchar_t*,void*,const wchar_t*,unsigned long*) PURE;
 // Activates the specified Windows Store app for the protocol contract (Windows.Protocol).
 // IShellItem doesn't exist. Replace with LPVOID
 STDMETHOD(ActivateForProtocol)(THIS_ const wchar_t*,void*,unsigned long*) PURE;
};
#undef INTERFACE
#ifdef __cplusplus
}
#endif

And here's the application to launch Windows 8 Application from desktop(File Apptest.cpp)
#include <stdio.h>
#include <Windows.h>
#include <ShObjIdl.h>
#include <string>
#ifndef _MSC_VER
#include "IApplicationActivationManager.h"
extern "C" __declspec(dllimport) HRESULT __stdcall CoAllowSetForegroundWindow(IUnknown *pUnk,LPVOID lpvReserved);
#endif
 
int main(int argc,char** argv) {
 IApplicationActivationManager* _;
 std::string __;
 size_t ___;
 if(argc<2) {
  printf("usage: %s <app package id>\r\n",argv[0]);
  return 1;
 }
 __=argv[1];
 CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED);
 CoCreateInstance(CLSID_ApplicationActivationManager,nullptr,CLSCTX_LOCAL_SERVER,IID_IApplicationActivationManager,(void**)&_);
 CoAllowSetForegroundWindow(_,nullptr);
 _->ActivateApplication(std::wstring(__.begin(),__.end()).c_str(),nullptr,AO_NONE,(DWORD*)&___);
 return 0;
}

Command Line i used to Compile: g++ -std=c++11 -o ConsoleApplication1.exe -L"%VSLIBDIR%" -static-libgcc -static-libstdc++ ConsoleApplication1/AppTest.cpp -lole32 -loleaut32
Set VSLIBDIR to your Windows 8 SDK Lib directory(for CoInitializeEx and CoAllowSetForegroundWindow)(Windows 8 SDK)

Note: Tested in Visual Studio 2012 and GCC v4.8.1
Note2: Enum app package id powershell command(source):
$installedapps = get-AppxPackage
foreach ($app in $installedapps)
{
    foreach ($id in (Get-AppxPackageManifest $app).package.applications.application.id)
    {
        $app.packagefamilyname + "!" + $id
    }
}

Monday, November 24, 2014

[C++|Windows 8]Get Accent & Background Color from Desktop Application

Windows 8 has some great features. Specially in the Metro design with some nice colors. This code will show how to get current used(selected) color in your start screen(personalization)


#include <windows.h>
#include <iostream>
 
typedef struct PersonalizationColor {
 int r;
 int g;
 int b;
} PersonalizationColor;
 
static const unsigned char ColorSet_Version3[25][2][3] = {    // Table for Accent & Background color in Windows 8
 {{37,37,37},{244,179,0}},
 {{37,37,37},{120,186,0}},
 {{37,37,37},{38,115,236}},
 {{37,37,37},{174,17,61}},
 {{46,23,0},{99,47,0}},
 {{78,0,0},{176,30,0}},
 {{78,0,56},{193,0,79}},
 {{45,0,78},{114,0,172}},
 {{31,0,104},{70,23,180}},
 {{0,30,78},{0,106,193}},
 {{0,77,96},{0,130,135}},
 {{0,74,0},{25,153,0}},
 {{21,153,42},{0,193,63}},
 {{229,108,25},{255,152,29}},
 {{184,27,27},{255,46,18}},
 {{184,27,108},{255,29,119}},
 {{105,27,184},{170,64,255}},
 {{27,88,184},{31,174,255}},
 {{86,156,227},{86,197,255}},
 {{0,170,170},{0,216,204}},
 {{131,186,31},{145,209,0}},
 {{211,157,9},{225,183,0}},
 {{224,100,183},{255,118,188}},
 {{105,105,105},{0,164,164}},
 {{105,105,105},{255,125,35}}
};
 
typedef struct windows_version {
 int major;    // CurrentVersion
 int minor;    // CurrentVersion
 int build_number;  // CurrentBuildNumber
 char name[256];   // ProductName
 char service_pack[256]; // CSDVersion(if exist)
 char edition[128];  // EditionID(if exist)
} windows_version;
 
int get_winver(windows_version* ptr) {
 HKEY temp;
 unsigned char CurrentVersion[8];
 long long long_temp=8;
 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows NT\\CurrentVersion",0,KEY_READ,&temp)==ERROR_SUCCESS) {
  int a=0;
  if(RegQueryValueEx(temp,"CurrentVersion",0,nullptr,CurrentVersion,(LPDWORD)&long_temp)!=ERROR_SUCCESS)
   return 0;
  double current_version=strtod((char*)CurrentVersion,nullptr);
  ptr->major=(int)floor(current_version);
  ptr->minor=(int)floor(current_version*10.0)-ptr->major*10;
  long_temp=8;
  memset(CurrentVersion,0,8);
  if((a=RegQueryValueEx(temp,"CurrentBuildNumber",0,nullptr,CurrentVersion,(LPDWORD)&long_temp))!=ERROR_SUCCESS)
   return 0;
  ptr->build_number=atoi((char*)CurrentVersion);
  long_temp=256;
  if(RegQueryValueEx(temp,"ProductName",0,nullptr,(LPBYTE)ptr->name,(LPDWORD)&long_temp)!=ERROR_SUCCESS)
   return 0;
  int* from_lt=(int*)&long_temp+4;
  long_temp=256;
  *from_lt=RegQueryValueEx(temp,"CSDVersion",0,nullptr,(LPBYTE)ptr->service_pack,(LPDWORD)&long_temp);
  if(*from_lt==ERROR_FILE_NOT_FOUND)
   memset(ptr->service_pack,0,256);
  else if(*from_lt!=ERROR_SUCCESS)
   return 0;
  long_temp=128;
  *from_lt=RegQueryValueEx(temp,"EditionID",0,nullptr,(LPBYTE)ptr->edition,(LPDWORD)&long_temp);
  if(*from_lt==ERROR_FILE_NOT_FOUND)
   memset(ptr->edition,0,128);
  else if(*from_lt!=ERROR_SUCCESS)
   return 0;
 } else
  return 0;
 RegCloseKey(temp);
 return 1;
}
 
bool Win8GetAccentColor(PersonalizationColor* col) {
 windows_version win;
 get_winver(&win);
 if(win.major>=6 && (win.minor>=2 && win.minor<=3)) {
  HKEY temp;
  int r=0;
  if((r=RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent",0,KEY_READ,&temp))==ERROR_SUCCESS) {
   auto accent_color=0UL;
   auto buf=4UL;
   if(win.minor==2) {
    if((r=RegQueryValueExA(temp,"ColorSet_Version3",nullptr,nullptr,(LPBYTE)&accent_color,&buf))==ERROR_SUCCESS) {
     col->r=ColorSet_Version3[accent_color][1][0];
     col->g=ColorSet_Version3[accent_color][1][1];
     col->b=ColorSet_Version3[accent_color][1][2];
     RegCloseKey(temp);
     return true;
    } else {
     RegCloseKey(temp);
     return false;
    }
   } else {
    if((r=RegQueryValueExA(temp,"AccentColor",nullptr,nullptr,(LPBYTE)&accent_color,&buf))==ERROR_SUCCESS) {
     col->r=GetRValue(accent_color);
     col->g=GetGValue(accent_color);
     col->b=GetBValue(accent_color);
     RegCloseKey(temp);
     return true;
    } else {
     RegCloseKey(temp);
     return false;
    }
   }
  } else
   return false;
 } else
  return false;
}
 
bool Win8GetBackgroundColor(PersonalizationColor* col) {
 windows_version win;
 get_winver(&win);
 if(win.major>=6 && (win.minor>=2 && win.minor<=3)) {
  HKEY temp;
  int r=0;
  if((r=RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent",0,KEY_READ,&temp))==ERROR_SUCCESS) {
   auto accent_color=0UL;
   auto buf=4UL;
   if(win.minor==2) {
    if((r=RegQueryValueExA(temp,"ColorSet_Version3",nullptr,nullptr,(LPBYTE)&accent_color,&buf))==ERROR_SUCCESS) {
     col->r=ColorSet_Version3[accent_color][0][0];
     col->g=ColorSet_Version3[accent_color][0][1];
     col->b=ColorSet_Version3[accent_color][0][2];
     RegCloseKey(temp);
     return 3;
    } else {
     RegCloseKey(temp);
     return true;
    }
   } else {
    if((r=RegQueryValueExA(temp,"StartColor",nullptr,nullptr,(LPBYTE)&accent_color,&buf))==ERROR_SUCCESS) {
     col->r=GetRValue(accent_color);
     col->g=GetGValue(accent_color);
     col->b=GetBValue(accent_color);
     RegCloseKey(temp);
     return true;
    } else {
     RegCloseKey(temp);
     return false;
    }
   }
  } else {
   return false;
  }
 } else
  return false;
}
 
int main() {
 PersonalizationColor accent;
 PersonalizationColor background;
 if(!Win8GetAccentColor(&accent)) {
  std::cerr << "Cannot get accent color!" << endl;
  return 1;
 }
 if(!Win8GetBackgroundColor(&background)) {
  std::cerr << "Cannot get background color!" << endl;
  return 1;
 }
 std::cout << "Accent: " << accent.r << "," << accent.g << "," << accent.g << endl << "Background: " << background.r << "," << background.g << "," << background.b << endl;
 return 0;
}

Note1: It also work in Windows 8.1 without any edits
Note2: It can be ported to C with some editing.
Note3: I give a bonus code. You can use get_winver to get windows version(which i think is better than GetVersionEx)