Skip to content

Commit

Permalink
Add Linux Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Csharpenge committed Apr 10, 2023
1 parent 5bbffab commit 6ebc0b7
Show file tree
Hide file tree
Showing 153 changed files with 33,590 additions and 22 deletions.
3 changes: 3 additions & 0 deletions Plugins/UFFmpeg/Source/UFFmpeg/Private/EncoderThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ FEncoderThread::~FEncoderThread()

bool FEncoderThread::Init()
{
counter = 0;
return true;
}

Expand Down Expand Up @@ -140,12 +141,14 @@ void FEncoderThread::RunEncode()
if (IsNeedEncode)
EncodeVideo();
}

}

void FEncoderThread::EncodeVideo()
{
if (video_data)
{
counter++;
video_encode_delegate.ExecuteIfBound(video_data);
video_data = nullptr;
}
Expand Down
50 changes: 35 additions & 15 deletions Plugins/UFFmpeg/Source/UFFmpeg/Private/FFmpegDirector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "EncodeData.h"
#include "Logging/LogVerbosity.h"
#include "Containers/Ticker.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
//#include "Editor.h"
#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"

Expand All @@ -19,10 +21,8 @@
#include "RHI.h"
#include "Misc/CoreDelegates.h"
#include "GameDelegates.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
#include "D3D12RHI.h"
#include <Kismet/GameplayStatics.h>
#include "ImageUtils.h"



Expand Down Expand Up @@ -112,16 +112,21 @@ void UFFmpegDirector::Begin_Receive_AudioData(UWorld* world)

void UFFmpegDirector::Initialize_Director(UWorld* World, int32 VideoLength, FString OutFileName, bool UseGPU, FString VideoFilter, int VideoFps, int VideoBitRate, float AudioDelay, float SoundVolume)
{

avformat_network_init();

// Notice end

FileAddr = OutFileName;
audio_delay = AudioDelay;
video_fps = VideoFps;
Video_Tick_Time = float(1) / float(video_fps);
TotalFrame = VideoLength * VideoFps;
TotalFrame = VideoLength;
FrameCount = 0;
FD_world = World;
audio_volume = SoundVolume;
finishVideocounter = 0;
finishAudiocounter = 0;

gameWindow = GEngine->GameViewport->GetWindow().Get();

Expand Down Expand Up @@ -181,7 +186,7 @@ void UFFmpegDirector::Initialize_Director(UWorld* World, int32 VideoLength, FStr
Begin_Receive_VideoData();
Begin_Receive_AudioData(World);

//End PIE deleate and tick delegate
//End PIE delegate and tick delegate
//AddEndFunction();
AddTickFunction();
}
Expand Down Expand Up @@ -235,7 +240,7 @@ void UFFmpegDirector::Stop(UWorld* _world)
delete Runnable;
Runnable = nullptr;

if (AudioDevice)
if (AudioDevice && this!=nullptr)
{
AudioDevice->UnregisterSubmixBufferListener(this);
}
Expand All @@ -247,6 +252,11 @@ void UFFmpegDirector::Stop(UWorld* _world)
FMemory::Free(outs[1]);
FMemory::Free(buff_bgr);

/* Only in Test, Quit game after Finish.
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
UKismetSystemLibrary::QuitGame(_world, PlayerController, EQuitPreference::Quit, true);
*/

// Tell us the file convent finish.
OnRecordFinish.Broadcast(FileAddr);
}
Expand All @@ -263,7 +273,10 @@ bool UFFmpegDirector::CheckThreadJobDone(float time)
{
if (Runnable->IsQueneEmpty())
{
Stop(FD_world);
if (finishAudiocounter >= TotalFrame && finishVideocounter >= TotalFrame)
{
Stop(FD_world);
}
}
return true;
}
Expand All @@ -277,6 +290,7 @@ void UFFmpegDirector::AddEndFunction()
// if(GameMode == EWorldType::PIE)
// FEditorDelegates::EndPIE.AddUObject(this, &UFFmpegDirector::EndWindowReader);

// Stop Recorder when get enough frame.
}

void UFFmpegDirector::AddTickFunction()
Expand Down Expand Up @@ -310,10 +324,10 @@ void UFFmpegDirector::GetScreenVideoData()
list.ReadSurfaceData(GameTexture, Rect, Data, FReadSurfaceDataFlags());

uint32* TextureData = (uint32*)FMemory::Malloc(4 * Rect.Width() * Rect.Height());

uint32* RowFlag = TextureData;
// Unsure but it work, I don't know why
LolStride = width*4;
LolStride = width * 4;

for (int row = 0; row < Rect.Height(); row++)
{
Expand All @@ -332,7 +346,7 @@ void UFFmpegDirector::GetScreenVideoData()
}

// DirectX 12 & Vulkan end

}

void UFFmpegDirector::CreateEncodeThread()
Expand All @@ -347,7 +361,7 @@ void UFFmpegDirector::CreateEncodeThread()

void UFFmpegDirector::Create_Audio_Encoder(const char* audioencoder_name)
{
AVCodec* audioencoder_codec;
const AVCodec* audioencoder_codec;
audioencoder_codec = avcodec_find_encoder_by_name(audioencoder_name);
out_audio_stream = avformat_new_stream(out_format_context, audioencoder_codec);
audio_index = out_audio_stream->index;
Expand All @@ -358,7 +372,7 @@ void UFFmpegDirector::Create_Audio_Encoder(const char* audioencoder_name)
check(false);
}
audio_encoder_codec_context->codec_id = AV_CODEC_ID_AAC;
audio_encoder_codec_context->bit_rate = 120000;
audio_encoder_codec_context->bit_rate = 192000;
audio_encoder_codec_context->codec_type = AVMEDIA_TYPE_AUDIO;
audio_encoder_codec_context->sample_rate = 48000;
audio_encoder_codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
Expand All @@ -384,7 +398,7 @@ void UFFmpegDirector::Create_Audio_Encoder(const char* audioencoder_name)

void UFFmpegDirector::Create_Video_Encoder(bool is_use_NGPU, const char* out_file_name, int bit_rate)
{
AVCodec *encoder_codec;
const AVCodec *encoder_codec;
int ret;

if (is_use_NGPU)
Expand Down Expand Up @@ -487,7 +501,7 @@ void UFFmpegDirector::Create_Video_Encoder(bool is_use_NGPU, const char* out_fil

void UFFmpegDirector::Video_Frame_YUV_From_BGR(uint8_t *rgb)
{
const int in_linesize[1] = { 3 * width };
const int in_linesize[1] = { 3 * (int)width };
sws_scale(sws_context, (const uint8_t * const *)&rgb, in_linesize, 0,
height, video_frame->data, video_frame->linesize);
video_frame->width = out_width;
Expand Down Expand Up @@ -553,6 +567,7 @@ void UFFmpegDirector::Encode_Audio_Frame(uint8_t *rgb)
av_write_frame(out_format_context, audio_pkt);
av_packet_unref(audio_pkt);
}
finishAudiocounter++;
}

void UFFmpegDirector::Encode_Video_Frame(uint8_t *rgb)
Expand All @@ -569,7 +584,8 @@ void UFFmpegDirector::Encode_Video_Frame(uint8_t *rgb)
for (Col = 0; Col < width; ++Col)
{
uint32 EncodedPixel = *PixelPtr;
// AV_PIX_FMT_BGR24
// AV_PIX_FMT_BGR24 这里暂时转换为BGR
// AV_PIX_FMT_RGB24 掉帧严重 暂时不知道为什么
*(buff_bgr + 2) = (EncodedPixel >> 2) & 0xFF;
*(buff_bgr + 1) = (EncodedPixel >> 12) & 0xFF;
*(buff_bgr) = (EncodedPixel >> 22) & 0xFF;
Expand Down Expand Up @@ -624,6 +640,10 @@ void UFFmpegDirector::Encode_Video_Frame(uint8_t *rgb)
}
}
av_frame_unref(filt_frame);


UE_LOG(LogTemp, Log, TEXT("Frame %d Encode Finish"), finishVideocounter);
finishVideocounter++;
}

void UFFmpegDirector::Encode_SetCurrentAudioTime(uint8_t* rgb)
Expand Down
2 changes: 1 addition & 1 deletion Plugins/UFFmpeg/Source/UFFmpeg/Private/UFFmpeg.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.

#include "Uffmpeg.h"
#include "UFFmpeg.h"
#include "Interfaces/IPluginManager.h"
#include "Core.h"
extern "C" {
Expand Down
2 changes: 2 additions & 0 deletions Plugins/UFFmpeg/Source/UFFmpeg/Public/EncoderThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,7 @@ class UFFMPEG_API FEncoderThread :public FRunnable
UCircleQueue* audio_queue;
UCircleQueue* audio_time_queue;

int counter = 0;

uint8* video_data=nullptr;
};
6 changes: 5 additions & 1 deletion Plugins/UFFmpeg/Source/UFFmpeg/Public/FFmpegDirector.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ class UFFMPEG_API UFFmpegDirector:public UObject,public ISubmixBufferListener

UFFmpegDirector();
virtual ~UFFmpegDirector();
UFUNCTION(BlueprintCallable)

UFUNCTION(BlueprintCallable, Category = "FFmpeg")
void Initialize_Director(UWorld* World, int32 VideoLength, FString OutFileName, bool UseGPU,FString VideoFilter,int VideoFps, int VideoBitRate, float AudioDelay,float SoundVolume);

void Begin_Receive_AudioData(UWorld* world);
void Begin_Receive_VideoData();

Expand Down Expand Up @@ -107,6 +109,8 @@ class UFFMPEG_API UFFmpegDirector:public UObject,public ISubmixBufferListener
uint32 out_width;
uint32 out_height;

uint32 finishVideocounter = 0;
uint32 finishAudiocounter = 0;

FTexture2DRHIRef GameTexture;

Expand Down
28 changes: 24 additions & 4 deletions Plugins/UFFmpeg/Source/UFFmpeg/UFFmpeg.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public UFFmpeg(ReadOnlyTargetRules Target) : base(Target)
{

string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "x64" : "Win32";
string LibrariesPath = Path.Combine(Path.Combine(Path.Combine(ThirdPartyPath, "ffmpeg", "lib"), "vs"), PlatformString);
string LibrariesPath = Path.Combine(Path.Combine(Path.Combine(ThirdPartyPath, "ffmpeg", "lib"), "vs"), PlatformString);

PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "avcodec.lib"));
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "avdevice.lib"));
Expand Down Expand Up @@ -60,8 +60,27 @@ public UFFmpeg(ReadOnlyTargetRules Target) : base(Target)
}

}
// Include path
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "ffmpeg", "include"));
if (Target.Platform == UnrealTargetPlatform.Linux)
{
string LibrariesPath = Path.Combine(Path.Combine(ThirdPartyPath, "ffmpeg", "lib"), "amd64");

System.Console.WriteLine("... LibrariesPath -> " + LibrariesPath);

string[] libs = { "libavcodec.a", "libavdevice.a", "libavfilter.a", "libavformat.a", "libavutil.a", "libswresample.a", "libswscale.a", "libpostproc.a" };
foreach (string lib in libs)
{
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, lib));
RuntimeDependencies.Add(Path.Combine(LibrariesPath, lib), StagedFileType.NonUFS);
}

// Include path Linux
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "ffmpeg", "include", "amd64"));
}
else
{
// Include path
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "ffmpeg", "include"));
}
PublicIncludePaths.Add(Path.Combine(Directory.GetCurrentDirectory(), "Runtime","AudioMixer","Private"));


Expand All @@ -78,15 +97,16 @@ public UFFmpeg(ReadOnlyTargetRules Target) : base(Target)
new string[]
{
"CoreUObject",
"Core",
"Engine",
"Slate",
"SlateCore",
"Projects",
"Engine",
"RHI",
"RHICore",
/*"UnrealEd",*/
"RenderCore",
"D3D12RHI"
// ... add private dependencies that you statically link with here ...
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* AC-3 parser prototypes
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef AVCODEC_AC3_PARSER_H
#define AVCODEC_AC3_PARSER_H

#include <stddef.h>
#include <stdint.h>

/**
* Extract the bitstream ID and the frame size from AC-3 data.
*/
int av_ac3_parse_header(const uint8_t *buf, size_t size,
uint8_t *bitstream_id, uint16_t *frame_size);


#endif /* AVCODEC_AC3_PARSER_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef AVCODEC_ADTS_PARSER_H
#define AVCODEC_ADTS_PARSER_H

#include <stddef.h>
#include <stdint.h>

#define AV_AAC_ADTS_HEADER_SIZE 7

/**
* Extract the number of samples and frames from AAC data.
* @param[in] buf pointer to AAC data buffer
* @param[out] samples Pointer to where number of samples is written
* @param[out] frames Pointer to where number of frames is written
* @return Returns 0 on success, error code on failure.
*/
int av_adts_header_parse(const uint8_t *buf, uint32_t *samples,
uint8_t *frames);

#endif /* AVCODEC_ADTS_PARSER_H */
Loading

0 comments on commit 6ebc0b7

Please sign in to comment.