added CTS padding, fixed graphics capture memory leak, fixed graphics capture crash
This commit is contained in:
parent
30fab1a6b7
commit
cb2a91d3be
23
ChangeLog
23
ChangeLog
@ -1,10 +1,31 @@
|
|||||||
(yyyy-mm-dd)
|
(yyyy-mm-dd)
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
2012-11-25 - 0.448 (alpha)
|
||||||
|
* Fixed memory leak caused by the mouse cursor data not being
|
||||||
|
freed
|
||||||
|
* Fixed a potential crash that can happen to both the game and
|
||||||
|
the application in certain cases
|
||||||
|
* Padded CTS values by 75ms to compensate for any negative CTS
|
||||||
|
deviations
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
2012-11-23 - 0.447 (alpha)
|
||||||
|
* Changed the game capture cursor to use a regular texture
|
||||||
|
rather than use a GDI texture, GDI texture went screwy
|
||||||
|
on some GPUs, so rendered it to a DIB section instead
|
||||||
|
and just copied the results
|
||||||
|
* More reverts and adjustments with the frame drop code to
|
||||||
|
prevent annoying frame drops, will add new frame drop code
|
||||||
|
later
|
||||||
|
* Fixed a bug in the new librtmp code that would cause it to
|
||||||
|
crash
|
||||||
|
|
||||||
-------------------------------
|
-------------------------------
|
||||||
2012-11-22 - 0.446 (alpha)
|
2012-11-22 - 0.446 (alpha)
|
||||||
* Finally just about completed game capture (wow was that a
|
* Finally just about completed game capture (wow was that a
|
||||||
crazy adventure)
|
crazy adventure)
|
||||||
* Added GIF supprot to bitmap image source
|
* Added GIF support to bitmap image source
|
||||||
* Added stream delay feature
|
* Added stream delay feature
|
||||||
* Adde option to allow users to use up to 120 FPS (if they're
|
* Adde option to allow users to use up to 120 FPS (if they're
|
||||||
crazy)
|
crazy)
|
||||||
|
@ -104,24 +104,31 @@ LRESULT WINAPI GraphicsCaptureSource::ReceiverWindowProc(HWND hwnd, UINT message
|
|||||||
|
|
||||||
case RECEIVER_NEWCAPTURE:
|
case RECEIVER_NEWCAPTURE:
|
||||||
{
|
{
|
||||||
GraphicsCaptureSource *source = (GraphicsCaptureSource*)GetWindowLongPtr(hwnd, 0);
|
CaptureWindowData *data = (CaptureWindowData*)GetWindowLongPtr(hwnd, 0);
|
||||||
if(source)
|
if(data->source)
|
||||||
source->NewCapture((LPVOID)lParam);
|
data->source->NewCapture((LPVOID)lParam);
|
||||||
}
|
}
|
||||||
return API->GetMaxFPS();
|
return API->GetMaxFPS();
|
||||||
|
|
||||||
case RECEIVER_ENDCAPTURE:
|
case RECEIVER_ENDCAPTURE:
|
||||||
{
|
{
|
||||||
GraphicsCaptureSource *source = (GraphicsCaptureSource*)GetWindowLongPtr(hwnd, 0);
|
CaptureWindowData *data = (CaptureWindowData*)GetWindowLongPtr(hwnd, 0);
|
||||||
if(source)
|
if(data->source)
|
||||||
{
|
{
|
||||||
API->EnterSceneMutex();
|
API->EnterSceneMutex();
|
||||||
source->EndCapture();
|
data->source->EndCapture();
|
||||||
API->LeaveSceneMutex();
|
API->LeaveSceneMutex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
{
|
||||||
|
CaptureWindowData *data = (CaptureWindowData*)GetWindowLongPtr(hwnd, 0);
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
@ -236,7 +243,8 @@ void GraphicsCaptureSource::BeginScene()
|
|||||||
if(bCaptureMouse && data->GetInt(TEXT("invertMouse")))
|
if(bCaptureMouse && data->GetInt(TEXT("invertMouse")))
|
||||||
invertShader = CreatePixelShaderFromFile(TEXT("shaders\\InvertTexture.pShader"));
|
invertShader = CreatePixelShaderFromFile(TEXT("shaders\\InvertTexture.pShader"));
|
||||||
|
|
||||||
hwndReceiver = CreateWindow(RECEIVER_WINDOWCLASS, NULL, 0, 0, 0, 0, 0, 0, 0, hinstMain, this);
|
windowData = new CaptureWindowData(this);
|
||||||
|
hwndReceiver = CreateWindow(RECEIVER_WINDOWCLASS, NULL, 0, 0, 0, 0, 0, 0, 0, hinstMain, windowData);
|
||||||
|
|
||||||
AttemptCapture();
|
AttemptCapture();
|
||||||
}
|
}
|
||||||
@ -326,6 +334,9 @@ void GraphicsCaptureSource::EndScene()
|
|||||||
hwndSender = NULL;
|
hwndSender = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(windowData)
|
||||||
|
windowData->source = NULL;
|
||||||
|
|
||||||
if(hwndReceiver)
|
if(hwndReceiver)
|
||||||
{
|
{
|
||||||
DestroyWindow(hwndReceiver);
|
DestroyWindow(hwndReceiver);
|
||||||
@ -461,6 +472,7 @@ void GraphicsCaptureSource::Render(const Vect2 &pos, const Vect2 &size)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
HICON hIcon = CopyIcon(ci.hCursor);
|
HICON hIcon = CopyIcon(ci.hCursor);
|
||||||
|
hCurrentCursor = ci.hCursor;
|
||||||
|
|
||||||
delete cursorTexture;
|
delete cursorTexture;
|
||||||
cursorTexture = NULL;
|
cursorTexture = NULL;
|
||||||
@ -480,6 +492,8 @@ void GraphicsCaptureSource::Render(const Vect2 &pos, const Vect2 &size)
|
|||||||
cursorTexture = CreateTexture(size, size, GS_BGRA, lpData, FALSE);
|
cursorTexture = CreateTexture(size, size, GS_BGRA, lpData, FALSE);
|
||||||
if(cursorTexture)
|
if(cursorTexture)
|
||||||
bMouseCaptured = true;
|
bMouseCaptured = true;
|
||||||
|
|
||||||
|
Free(lpData);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteObject(ii.hbmColor);
|
DeleteObject(ii.hbmColor);
|
||||||
|
@ -19,8 +19,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
class GraphicsCaptureSource;
|
||||||
|
|
||||||
|
struct CaptureWindowData
|
||||||
|
{
|
||||||
|
inline CaptureWindowData(GraphicsCaptureSource *source) : source(source) {}
|
||||||
|
GraphicsCaptureSource *source;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class GraphicsCaptureSource : public ImageSource
|
class GraphicsCaptureSource : public ImageSource
|
||||||
{
|
{
|
||||||
|
CaptureWindowData *windowData;
|
||||||
GraphicsCaptureMethod *capture;
|
GraphicsCaptureMethod *capture;
|
||||||
UINT cx, cy;
|
UINT cx, cy;
|
||||||
|
|
||||||
|
8
OBS.rc
8
OBS.rc
@ -617,8 +617,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,4,4,7
|
FILEVERSION 0,4,4,8
|
||||||
PRODUCTVERSION 0,4,4,7
|
PRODUCTVERSION 0,4,4,8
|
||||||
FILEFLAGSMASK 0x17L
|
FILEFLAGSMASK 0x17L
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -634,12 +634,12 @@ BEGIN
|
|||||||
BLOCK "041104b0"
|
BLOCK "041104b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "FileDescription", "Open Broadcaster Software"
|
VALUE "FileDescription", "Open Broadcaster Software"
|
||||||
VALUE "FileVersion", "0, 4, 4, 7"
|
VALUE "FileVersion", "0, 4, 4, 8"
|
||||||
VALUE "InternalName", "OBS"
|
VALUE "InternalName", "OBS"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2012"
|
VALUE "LegalCopyright", "Copyright (C) 2012"
|
||||||
VALUE "OriginalFilename", "OBS.exe"
|
VALUE "OriginalFilename", "OBS.exe"
|
||||||
VALUE "ProductName", "Open Broadcaster Software"
|
VALUE "ProductName", "Open Broadcaster Software"
|
||||||
VALUE "ProductVersion", "0, 4, 4, 7"
|
VALUE "ProductVersion", "0, 4, 4, 8"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -208,6 +208,10 @@ public:
|
|||||||
int timeOffset = int(INT64(picOut.i_pts+delayTime)-INT64(outputTimestamp));
|
int timeOffset = int(INT64(picOut.i_pts+delayTime)-INT64(outputTimestamp));
|
||||||
//Log(TEXT("dts: %d, pts: %d, timestamp: %d, offset: %d"), picOut.i_dts, picOut.i_pts, outputTimestamp, timeOffset);
|
//Log(TEXT("dts: %d, pts: %d, timestamp: %d, offset: %d"), picOut.i_dts, picOut.i_pts, outputTimestamp, timeOffset);
|
||||||
|
|
||||||
|
timeOffset += 75; //100 is negative CTS padding for VFR
|
||||||
|
if(timeOffset < 0) //this is very unlikely with the padding
|
||||||
|
timeOffset = 0;
|
||||||
|
|
||||||
timeOffset = htonl(timeOffset);
|
timeOffset = htonl(timeOffset);
|
||||||
|
|
||||||
BYTE *timeOffsetAddr = ((BYTE*)&timeOffset)+1;
|
BYTE *timeOffsetAddr = ((BYTE*)&timeOffset)+1;
|
||||||
@ -233,7 +237,7 @@ public:
|
|||||||
*(DWORD*)(SEIPacket+5) = htonl(newPayloadSize);
|
*(DWORD*)(SEIPacket+5) = htonl(newPayloadSize);
|
||||||
mcpy(SEIPacket+9, nal.p_payload+skipBytes, newPayloadSize);
|
mcpy(SEIPacket+9, nal.p_payload+skipBytes, newPayloadSize);
|
||||||
}
|
}
|
||||||
else if(nal.i_type == NAL_SLICE_IDR || nal.i_type == NAL_SLICE)
|
else if(nal.i_type == NAL_SLICE_IDR || nal.i_type == NAL_SLICE /*|| nal.i_type == NAL_SEI*/)
|
||||||
{
|
{
|
||||||
VideoPacket *newPacket = CurrentPackets.CreateNew();
|
VideoPacket *newPacket = CurrentPackets.CreateNew();
|
||||||
|
|
||||||
@ -244,7 +248,7 @@ public:
|
|||||||
int newPayloadSize = (nal.i_payload-skipBytes);
|
int newPayloadSize = (nal.i_payload-skipBytes);
|
||||||
newPacket->Packet.SetSize(9+newPayloadSize);
|
newPacket->Packet.SetSize(9+newPayloadSize);
|
||||||
|
|
||||||
newPacket->Packet[0] = ((nal.i_type == NAL_SLICE_IDR) ? 0x17 : 0x27);
|
newPacket->Packet[0] = ((nal.i_type == NAL_SLICE_IDR || nal.i_type == NAL_SEI) ? 0x17 : 0x27);
|
||||||
newPacket->Packet[1] = 1;
|
newPacket->Packet[1] = 1;
|
||||||
mcpy(newPacket->Packet+2, timeOffsetAddr, 3);
|
mcpy(newPacket->Packet+2, timeOffsetAddr, 3);
|
||||||
*(DWORD*)(newPacket->Packet+5) = htonl(newPayloadSize);
|
*(DWORD*)(newPacket->Packet+5) = htonl(newPayloadSize);
|
||||||
@ -302,6 +306,9 @@ public:
|
|||||||
|
|
||||||
x264_encoder_headers(x264, &nalOut, &nalNum);
|
x264_encoder_headers(x264, &nalOut, &nalNum);
|
||||||
|
|
||||||
|
int timeOffset = 0;//htonl(200);
|
||||||
|
BYTE *timeOffsetAddr = ((BYTE*)&timeOffset)+1;
|
||||||
|
|
||||||
for(int i=0; i<nalNum; i++)
|
for(int i=0; i<nalNum; i++)
|
||||||
{
|
{
|
||||||
x264_nal_t &nal = nalOut[i];
|
x264_nal_t &nal = nalOut[i];
|
||||||
@ -312,6 +319,7 @@ public:
|
|||||||
|
|
||||||
headerOut.OutputByte(0x17);
|
headerOut.OutputByte(0x17);
|
||||||
headerOut.OutputByte(0);
|
headerOut.OutputByte(0);
|
||||||
|
//headerOut.Serialize(timeOffsetAddr, 3);
|
||||||
headerOut.OutputByte(0);
|
headerOut.OutputByte(0);
|
||||||
headerOut.OutputByte(0);
|
headerOut.OutputByte(0);
|
||||||
headerOut.OutputByte(0);
|
headerOut.OutputByte(0);
|
||||||
|
@ -481,7 +481,7 @@ public:
|
|||||||
output.Serialize(IFrameIDs.Array(), IFrameIDs.Num()*sizeof(UINT));
|
output.Serialize(IFrameIDs.Array(), IFrameIDs.Num()*sizeof(UINT));
|
||||||
PopBox(); //stss
|
PopBox(); //stss
|
||||||
PushBox(output, DWORD_BE('ctts')); //list of composition time offsets
|
PushBox(output, DWORD_BE('ctts')); //list of composition time offsets
|
||||||
output.OutputDword(DWORD_BE(0x01000000)); //version (1) and flags (none)
|
output.OutputDword(0); //version (0) and flags (none)
|
||||||
output.OutputDword(fastHtonl(compositionOffsets.Num()));
|
output.OutputDword(fastHtonl(compositionOffsets.Num()));
|
||||||
for(UINT i=0; i<compositionOffsets.Num(); i++)
|
for(UINT i=0; i<compositionOffsets.Num(); i++)
|
||||||
{
|
{
|
||||||
|
@ -61,8 +61,8 @@ extern ConfigFile *AppConfig;
|
|||||||
extern OBS *App;
|
extern OBS *App;
|
||||||
extern TCHAR lpAppDataPath[MAX_PATH];
|
extern TCHAR lpAppDataPath[MAX_PATH];
|
||||||
|
|
||||||
#define OBS_VERSION 0x000447
|
#define OBS_VERSION 0x000448
|
||||||
#define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.447a"
|
#define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.448a"
|
||||||
#define OBS_VERSION_STRING TEXT(OBS_VERSION_STRING_ANSI)
|
#define OBS_VERSION_STRING TEXT(OBS_VERSION_STRING_ANSI)
|
||||||
|
|
||||||
#define OBS_WINDOW_CLASS TEXT("OBSWindowClass")
|
#define OBS_WINDOW_CLASS TEXT("OBSWindowClass")
|
||||||
|
@ -2255,15 +2255,15 @@ void OBS::MainCaptureLoop()
|
|||||||
if(pendingAudioFrames.Num())
|
if(pendingAudioFrames.Num())
|
||||||
{
|
{
|
||||||
//Log(TEXT("pending frames %u, (in milliseconds): %u"), pendingAudioFrames.Num(), pendingAudioFrames.Last().timestamp-pendingAudioFrames[0].timestamp);
|
//Log(TEXT("pending frames %u, (in milliseconds): %u"), pendingAudioFrames.Num(), pendingAudioFrames.Last().timestamp-pendingAudioFrames[0].timestamp);
|
||||||
while(pendingAudioFrames.Num() && pendingAudioFrames[0].timestamp < curTimeStamp)
|
while(pendingAudioFrames.Num() && pendingAudioFrames[0].timestamp+75 < curTimeStamp)
|
||||||
{
|
{
|
||||||
List<BYTE> &audioData = pendingAudioFrames[0].audioData;
|
List<BYTE> &audioData = pendingAudioFrames[0].audioData;
|
||||||
|
|
||||||
if(audioData.Num())
|
if(audioData.Num())
|
||||||
{
|
{
|
||||||
network->SendPacket(audioData.Array(), audioData.Num(), pendingAudioFrames[0].timestamp, PacketType_Audio);
|
network->SendPacket(audioData.Array(), audioData.Num(), pendingAudioFrames[0].timestamp+75, PacketType_Audio);
|
||||||
if(fileStream)
|
if(fileStream)
|
||||||
fileStream->AddPacket(audioData.Array(), audioData.Num(), pendingAudioFrames[0].timestamp, PacketType_Audio);
|
fileStream->AddPacket(audioData.Array(), audioData.Num(), pendingAudioFrames[0].timestamp+75, PacketType_Audio);
|
||||||
|
|
||||||
audioData.Clear();
|
audioData.Clear();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user