SpringBoot實現國際化中英文翻譯 配置IDEA 1.設置編碼為UTF-8 2.在resources目錄下創建 i18n 文件夾 internationalization簡寫 在文件夾中創建配置文件login.properties 再創建login_zh_CN.properties 配 ...
從output入手,梳理一下obs output的結構。這裡需要仔細過一遍,因為接下來需要把視頻寫入Unreal的Rendertarget對象,來渲染成材質。
音頻也需要單獨接入到Unreal引擎中。梳理的過程中,非核心的邏輯和標記我會去掉,只保留主幹。
//碧麟備註版 struct obs_output { // obs上下文 struct obs_context_data context; // 輸出結構信息 struct obs_output_info info; /* indicates ownership of the info.id buffer */ bool owns_info_id; int64_t video_offset; int64_t audio_offsets[MAX_OUTPUT_AUDIO_ENCODERS]; int64_t highest_audio_ts; int64_t highest_video_ts; pthread_t end_data_capture_thread; int total_frames; //視頻信息指針 video_t *video; //音頻信息指針 audio_t *audio; //視頻編碼器 obs_encoder_t *video_encoder; //音頻編碼器,因為支持多路音頻合成,所以這裡用的是數組 obs_encoder_t *audio_encoders[MAX_OUTPUT_AUDIO_ENCODERS]; struct circlebuf audio_buffer[MAX_AUDIO_MIXES][MAX_AV_PLANES]; uint64_t audio_start_ts; uint64_t video_start_ts; size_t audio_size; size_t planes; size_t sample_rate; size_t total_audio_frames; uint32_t scaled_width; uint32_t scaled_height; struct video_scale_info video_conversion; struct audio_convert_info audio_conversion; struct circlebuf caption_data; float audio_data[MAX_AUDIO_CHANNELS][AUDIO_OUTPUT_FRAMES]; };
看完上面的output結構,我們實際調試一下,點擊“屏幕錄製”,會進入obs_output_start這個函數,這個函數是個馬甲,簡單帶過
//碧麟精簡標註版
bool obs_output_start(obs_output_t *output)
{
bool encoded;
bool has_service;
encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
if (encoded && output->delay_sec) {
//延遲運行
return obs_output_delay_start(output);
} else {
//實際運行
if (obs_output_actual_start(output)) {
//發送starting signal
do_output_signal(output, "starting");
return true;
}
return false;
}
}
接下來是重點
//碧麟精簡批註版
bool obs_output_actual_start(obs_output_t *output)
{
bool success = false;
// 第一步,調用outp->info.start,參數是output->context.data
if (output->context.data)
success = output->info.start(output->context.data);
if (success && output->video) {
output->starting_frame_count =
video_output_get_total_frames(output->video);
output->starting_drawn_count = obs->video.total_frames;
output->starting_lagged_count = obs->video.lagged_frames;
}
if (os_atomic_load_long(&output->delay_restart_refs))
os_atomic_dec_long(&output->delay_restart_refs);
output->caption_timestamp = 0;
circlebuf_free(&output->caption_data);
circlebuf_init(&output->caption_data);
return success;
}
第一步是,調用outp->info.start,參數是output->context.data
output->info.start應該是一個函數指針,定義如下
// 碧麟精簡批註版
// output_info結構 ,主要存儲函數指針
struct obs_output_info {
/* required */
const char *id;
uint32_t flags;
const char *(*get_name)(void *type_data);
//創建
void *(*create)(obs_data_t *settings, obs_output_t *output);
//銷毀
void (*destroy)(void *data);
//開始
bool (*start)(void *data);
//停止
void (*stop)(void *data, uint64_t ts);
void (*raw_video)(void *data, struct video_data *frame);
void (*raw_audio)(void *data, struct audio_data *frames);
void (*encoded_packet)(void *data, struct encoder_packet *packet);
//get預設設置
void (*get_defaults)(obs_data_t *settings);
//get屬性
obs_properties_t *(*get_properties)(void *data);
uint64_t (*get_total_bytes)(void *data);
int (*get_dropped_frames)(void *data);
void *type_data;
/* only used with encoded outputs, separated with semicolon */
const char *encoded_video_codecs;
const char *encoded_audio_codecs;
/* raw audio callback for multi track outputs */
void (*raw_audio2)(void *data, size_t idx, struct audio_data *frames);
};
context定義如下
//context數據結構
struct obs_context_data {
char *name;
const char *uuid;
// 這個是最重要的
void *data;
obs_data_t *settings;
signal_handler_t *signals;
proc_handler_t *procs;
enum obs_obj_type type;
struct obs_weak_object *control;
DARRAY(obs_hotkey_id) hotkeys;
DARRAY(obs_hotkey_pair_id) hotkey_pairs;
obs_data_t *hotkey_data;
//多路傳輸使用,鏈表
struct obs_context_data *next;
struct obs_context_data **prev_next;
bool private;
};
這裡,data是context最重要的內容
因為我是用的ffmpeg多路傳輸做錄屏,所以data是一個ffmpeg_muxer
因此output->info.start(output->context.data)在這裡展開是這樣的結構
static bool ffmpeg_mux_start(void *data)
{
struct ffmpeg_muxer *stream = data;
//讀取設置
obs_data_t *settings = obs_output_get_settings(stream->output);
//實際開始執行多路傳輸
bool success = ffmpeg_mux_start_internal(stream, settings);
obs_data_release(settings);
return success;
}
//碧麟精簡批註版
static inline bool ffmpeg_mux_start_internal(struct ffmpeg_muxer *stream,
obs_data_t *settings)
{
//讀取保存路徑
//調試結果:C:/Users/86180/Videos/2023-03-16 13-36-11.mp4
const char *path = obs_data_get_string(settings, "path");
//設定保存路徑
update_encoder_settings(stream, path);
//網路版
if (stream->is_network) {
obs_service_t *service;
service = obs_output_get_service(stream->output);
if (!service)
return false;
path = obs_service_get_url(service);
stream->split_file = false;
} else {
//本地版
stream->max_time =
obs_data_get_int(settings, "max_time_sec") * 1000000LL;
stream->max_size = obs_data_get_int(settings, "max_size_mb") *
(1024 * 1024);
stream->split_file = obs_data_get_bool(settings, "split_file");
stream->allow_overwrite =
obs_data_get_bool(settings, "allow_overwrite");
stream->cur_size = 0;
stream->sent_headers = false;
}
ts_offset_clear(stream);
//錄屏信息嘗試寫本地文件,確保文件可寫入
if (!stream->is_network) {
/* ensure output path is writable to avoid generic error
* message.
*
* TODO: remove once ffmpeg-mux is refactored to pass
* errors back */
FILE *test_file = os_fopen(path, "wb");
if (!test_file) {
set_file_not_readable_error(stream, settings, path);
return false;
}
fclose(test_file);
os_unlink(path);
}
//這裡會生成一個command
//"D:/dev/obs/obs-studio/build/rundir/Debug/bin/64bit/obs-ffmpeg-mux.exe" "C:/Users/86180/Videos/2023-03-16 14-58-19.mp4" 1 1 h264 850 1280 720 1 1 1 1 1 0 30 1 0 aac "simple_aac" 192 48000 1024 2 "" ""
//可以看出是使用外部程式進行錄屏
start_pipe(stream, path);
if (!stream->pipe) {
obs_output_set_last_error(
stream->output, obs_module_text("HelperProcessFailed"));
warn("Failed to create process pipe");
return false;
}
/* write headers and start capture */
os_atomic_set_bool(&stream->active, true);
os_atomic_set_bool(&stream->capturing, true);
stream->total_bytes = 0;
obs_output_begin_data_capture(stream->output, 0);
info("Writing file '%s'...", stream->path.array);
return true;
}
ffmpeg_mux實際工作核心邏輯都在這裡
可以看出錄屏是用這個外部程式obs-ffmpeg-mux.exe來進行的。
低調瀟灑的技術男