init
This commit is contained in:
125
Source/AudioVideoRecord/SimpleRecorder.h
Normal file
125
Source/AudioVideoRecord/SimpleRecorder.h
Normal file
@@ -0,0 +1,125 @@
|
||||
// SimpleRecorder.h — In-game gameplay recorder (Video + Audio + Mux)
|
||||
// Captures the Unreal back buffer & audio submix, pipes to FFmpeg/NVENC.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "Sound/SoundSubmix.h"
|
||||
#include "ISubmixBufferListener.h"
|
||||
#include "SimpleRecorder.generated.h"
|
||||
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// USimpleRecorder
|
||||
//
|
||||
// A UObject-based recorder you can create from Blueprint or C++.
|
||||
// • StartRecording() — begins video + audio capture
|
||||
// • StopRecording() — stops capture, writes .wav, muxes final .mp4
|
||||
//
|
||||
// Outputs (inside <ProjectDir>/Saved/Recordings/):
|
||||
// video_only.mp4 — NVENC-encoded H.264
|
||||
// audio_only.wav — PCM 16-bit
|
||||
// final_video_with_audio.mp4 — muxed result
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
UCLASS(BlueprintType)
|
||||
class AUDIOVIDEORECORD_API USimpleRecorder : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USimpleRecorder();
|
||||
|
||||
// ── Blueprint-callable API ───────────────────────────────────────
|
||||
/** Starts capturing video frames and audio. */
|
||||
UFUNCTION(BlueprintCallable, Category = "SimpleRecorder")
|
||||
void StartRecording();
|
||||
|
||||
/** Stops capturing. Saves audio_only.wav, then muxes the final file. */
|
||||
UFUNCTION(BlueprintCallable, Category = "SimpleRecorder")
|
||||
void StopRecording();
|
||||
|
||||
/** Returns true while recording is active. */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SimpleRecorder")
|
||||
bool IsRecording() const { return bIsRecording; }
|
||||
|
||||
// ── Configurable settings (edit before calling StartRecording) ───
|
||||
/** If true, capture resolution is auto-detected from the viewport at recording start. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
bool bAutoDetectResolution = true;
|
||||
|
||||
/** Capture width in pixels (ignored if bAutoDetectResolution is true). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
int32 CaptureWidth = 1920;
|
||||
|
||||
/** Capture height in pixels (ignored if bAutoDetectResolution is true). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
int32 CaptureHeight = 1080;
|
||||
|
||||
/** Target frames per second. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
int32 CaptureFPS = 60;
|
||||
|
||||
/** Video bitrate string for FFmpeg (e.g. "8M", "12M"). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
FString VideoBitrate = TEXT("8M");
|
||||
|
||||
/** Directory where output files are saved (absolute or project-relative). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
FString OutputDirectory;
|
||||
|
||||
/** Full path to ffmpeg.exe. If empty we look on the system PATH. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
FString FFmpegPath;
|
||||
|
||||
/** The audio submix to record. If null, the engine master submix is used. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SimpleRecorder|Settings")
|
||||
USoundSubmix* TargetSubmix = nullptr;
|
||||
|
||||
// ── Audio submix callback (forwarded from bridge) ──────────────
|
||||
void OnNewSubmixBuffer(
|
||||
const USoundSubmix* OwningSubmix,
|
||||
float* AudioData,
|
||||
int32 NumSamples,
|
||||
int32 NumChannels,
|
||||
const int32 SampleRate,
|
||||
double AudioClock);
|
||||
|
||||
protected:
|
||||
virtual void BeginDestroy() override;
|
||||
|
||||
private:
|
||||
// ── Internal helpers ─────────────────────────────────────────────
|
||||
void InitOutputPaths();
|
||||
FString GetFFmpegExecutable() const;
|
||||
|
||||
/** Called every frame on the render thread when the back buffer is ready. */
|
||||
void OnBackBufferReady(SWindow& SlateWindow, const FTextureRHIRef& BackBuffer);
|
||||
|
||||
/** Writes the captured audio buffer to a .wav file. */
|
||||
void SaveAudioToWav();
|
||||
|
||||
/** Runs FFmpeg to mux video_only.mp4 + audio_only.wav → final .mp4. */
|
||||
void MuxAudioVideo();
|
||||
|
||||
// ── State ────────────────────────────────────────────────────────
|
||||
bool bIsRecording = false;
|
||||
|
||||
// Video
|
||||
FDelegateHandle BackBufferDelegateHandle;
|
||||
FILE* FFmpegVideoPipe = nullptr;
|
||||
|
||||
// Audio — accumulated raw PCM data
|
||||
TArray<float> AudioBuffer; // interleaved float samples
|
||||
int32 AudioSampleRate = 48000;
|
||||
int32 AudioNumChannels = 2;
|
||||
FCriticalSection AudioBufferCritSection;
|
||||
|
||||
// Output file paths (computed once per recording session)
|
||||
FString VideoFilePath;
|
||||
FString AudioFilePath;
|
||||
FString FinalFilePath;
|
||||
|
||||
// Submix bridge (UObjects can't be TSharedRef, so we use a bridge)
|
||||
TSharedPtr<ISubmixBufferListener, ESPMode::ThreadSafe> SubmixBridge;
|
||||
};
|
||||
Reference in New Issue
Block a user