window-basic-main-outputs.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. #include <string>
  2. #include <QMessageBox>
  3. #include "window-basic-main.hpp"
  4. #include "window-basic-main-outputs.hpp"
  5. using namespace std;
  6. static void OBSStartStreaming(void *data, calldata_t *params)
  7. {
  8. BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
  9. QMetaObject::invokeMethod(output->main, "StreamingStart");
  10. UNUSED_PARAMETER(params);
  11. }
  12. static void OBSStopStreaming(void *data, calldata_t *params)
  13. {
  14. BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
  15. int code = (int)calldata_int(params, "code");
  16. QMetaObject::invokeMethod(output->main,
  17. "StreamingStop", Q_ARG(int, code));
  18. output->activeRefs--;
  19. }
  20. static void OBSStartRecording(void *data, calldata_t *params)
  21. {
  22. BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
  23. QMetaObject::invokeMethod(output->main, "RecordingStart");
  24. UNUSED_PARAMETER(params);
  25. }
  26. static void OBSStopRecording(void *data, calldata_t *params)
  27. {
  28. BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
  29. QMetaObject::invokeMethod(output->main, "RecordingStop");
  30. output->activeRefs--;
  31. UNUSED_PARAMETER(params);
  32. }
  33. /* ------------------------------------------------------------------------ */
  34. static OBSEncoder CreateAACEncoder(const char *name, size_t idx)
  35. {
  36. static const char *encoders[] = {
  37. "libfdk_aac",
  38. "ffmpeg_aac"
  39. };
  40. OBSEncoder result;
  41. for (const char *encoder : encoders) {
  42. result = obs_audio_encoder_create(encoder, name, nullptr, idx,
  43. nullptr);
  44. if (result) {
  45. obs_encoder_release(result);
  46. break;
  47. }
  48. }
  49. return result;
  50. }
  51. /* ------------------------------------------------------------------------ */
  52. struct SimpleOutput : BasicOutputHandler {
  53. OBSEncoder aac;
  54. OBSEncoder h264;
  55. SimpleOutput(OBSBasic *main_);
  56. virtual void Update() override;
  57. void SetupOutputs();
  58. virtual bool StartStreaming(obs_service_t *service) override;
  59. virtual bool StartRecording() override;
  60. virtual void StopStreaming() override;
  61. virtual void StopRecording() override;
  62. virtual bool StreamingActive() const override;
  63. virtual bool RecordingActive() const override;
  64. };
  65. SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
  66. {
  67. streamOutput = obs_output_create("rtmp_output", "simple_stream",
  68. nullptr, nullptr);
  69. if (!streamOutput)
  70. throw "Failed to create stream output (simple output)";
  71. obs_output_release(streamOutput);
  72. fileOutput = obs_output_create("flv_output", "simple_file_output",
  73. nullptr, nullptr);
  74. if (!fileOutput)
  75. throw "Failed to create recording output (simple output)";
  76. obs_output_release(fileOutput);
  77. h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr,
  78. nullptr);
  79. if (!h264)
  80. throw "Failed to create h264 encoder (simple output)";
  81. obs_encoder_release(h264);
  82. aac = CreateAACEncoder("simple_aac", 0);
  83. if (!aac)
  84. throw "Failed to create audio encoder (simple output)";
  85. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  86. "start", OBSStartStreaming, this);
  87. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  88. "stop", OBSStopStreaming, this);
  89. signal_handler_connect(obs_output_get_signal_handler(fileOutput),
  90. "start", OBSStartRecording, this);
  91. signal_handler_connect(obs_output_get_signal_handler(fileOutput),
  92. "stop", OBSStopRecording, this);
  93. }
  94. void SimpleOutput::Update()
  95. {
  96. obs_data_t *h264Settings = obs_data_create();
  97. obs_data_t *aacSettings = obs_data_create();
  98. int videoBitrate = config_get_uint(main->Config(), "SimpleOutput",
  99. "VBitrate");
  100. int videoBufsize = config_get_uint(main->Config(), "SimpleOutput",
  101. "VBufsize");
  102. int audioBitrate = config_get_uint(main->Config(), "SimpleOutput",
  103. "ABitrate");
  104. bool advanced = config_get_bool(main->Config(), "SimpleOutput",
  105. "UseAdvanced");
  106. bool useCBR = config_get_bool(main->Config(), "SimpleOutput",
  107. "UseCBR");
  108. bool useBufsize = config_get_bool(main->Config(), "SimpleOutput",
  109. "UseBufsize");
  110. const char *preset = config_get_string(main->Config(),
  111. "SimpleOutput", "Preset");
  112. const char *custom = config_get_string(main->Config(),
  113. "SimpleOutput", "x264Settings");
  114. obs_data_set_int(h264Settings, "bitrate", videoBitrate);
  115. obs_data_set_bool(h264Settings, "use_bufsize", useBufsize);
  116. obs_data_set_int(h264Settings, "buffer_size", videoBufsize);
  117. if (advanced) {
  118. obs_data_set_string(h264Settings, "preset", preset);
  119. obs_data_set_string(h264Settings, "x264opts", custom);
  120. obs_data_set_bool(h264Settings, "cbr", useCBR);
  121. } else {
  122. obs_data_set_bool(h264Settings, "cbr", true);
  123. }
  124. obs_data_set_int(aacSettings, "bitrate", audioBitrate);
  125. obs_service_apply_encoder_settings(main->GetService(),
  126. h264Settings, aacSettings);
  127. video_t *video = obs_get_video();
  128. enum video_format format = video_output_get_format(video);
  129. if (format != VIDEO_FORMAT_NV12 && format != VIDEO_FORMAT_I420)
  130. obs_encoder_set_preferred_video_format(h264, VIDEO_FORMAT_NV12);
  131. obs_encoder_update(h264, h264Settings);
  132. obs_encoder_update(aac, aacSettings);
  133. obs_data_release(h264Settings);
  134. obs_data_release(aacSettings);
  135. }
  136. inline void SimpleOutput::SetupOutputs()
  137. {
  138. SimpleOutput::Update();
  139. obs_encoder_set_video(h264, obs_get_video());
  140. obs_encoder_set_audio(aac, obs_get_audio());
  141. }
  142. bool SimpleOutput::StartStreaming(obs_service_t *service)
  143. {
  144. if (!Active())
  145. SetupOutputs();
  146. obs_output_set_video_encoder(streamOutput, h264);
  147. obs_output_set_audio_encoder(streamOutput, aac, 0);
  148. obs_output_set_service(streamOutput, service);
  149. bool reconnect = config_get_bool(main->Config(), "SimpleOutput",
  150. "Reconnect");
  151. int retryDelay = config_get_uint(main->Config(), "SimpleOutput",
  152. "RetryDelay");
  153. int maxRetries = config_get_uint(main->Config(), "SimpleOutput",
  154. "MaxRetries");
  155. if (!reconnect)
  156. maxRetries = 0;
  157. obs_output_set_reconnect_settings(streamOutput, maxRetries,
  158. retryDelay);
  159. if (obs_output_start(streamOutput)) {
  160. activeRefs++;
  161. return true;
  162. }
  163. return false;
  164. }
  165. bool SimpleOutput::StartRecording()
  166. {
  167. if (!Active())
  168. SetupOutputs();
  169. const char *path = config_get_string(main->Config(),
  170. "SimpleOutput", "FilePath");
  171. os_dir_t *dir = path ? os_opendir(path) : nullptr;
  172. if (!dir) {
  173. QMessageBox::information(main,
  174. QTStr("Output.BadPath.Title"),
  175. QTStr("Output.BadPath.Text"));
  176. return false;
  177. }
  178. os_closedir(dir);
  179. string strPath;
  180. strPath += path;
  181. char lastChar = strPath.back();
  182. if (lastChar != '/' && lastChar != '\\')
  183. strPath += "/";
  184. strPath += GenerateTimeDateFilename("flv");
  185. SetupOutputs();
  186. obs_output_set_video_encoder(fileOutput, h264);
  187. obs_output_set_audio_encoder(fileOutput, aac, 0);
  188. obs_data_t *settings = obs_data_create();
  189. obs_data_set_string(settings, "path", strPath.c_str());
  190. obs_output_update(fileOutput, settings);
  191. obs_data_release(settings);
  192. if (obs_output_start(fileOutput)) {
  193. activeRefs++;
  194. return true;
  195. }
  196. return false;
  197. }
  198. void SimpleOutput::StopStreaming()
  199. {
  200. obs_output_stop(streamOutput);
  201. }
  202. void SimpleOutput::StopRecording()
  203. {
  204. obs_output_stop(fileOutput);
  205. }
  206. bool SimpleOutput::StreamingActive() const
  207. {
  208. return obs_output_active(streamOutput);
  209. }
  210. bool SimpleOutput::RecordingActive() const
  211. {
  212. return obs_output_active(fileOutput);
  213. }
  214. /* ------------------------------------------------------------------------ */
  215. struct AdvancedOutput : BasicOutputHandler {
  216. OBSEncoder aacTrack[4];
  217. OBSEncoder h264Streaming;
  218. OBSEncoder h264Recording;
  219. bool ffmpegRecording;
  220. bool useStreamEncoder;
  221. AdvancedOutput(OBSBasic *main_);
  222. inline void UpdateStreamSettings();
  223. inline void UpdateRecordingSettings();
  224. inline void UpdateAudioSettings();
  225. virtual void Update() override;
  226. inline void SetupStreaming();
  227. inline void SetupRecording();
  228. inline void SetupFFmpeg();
  229. void SetupOutputs();
  230. virtual bool StartStreaming(obs_service_t *service) override;
  231. virtual bool StartRecording() override;
  232. virtual void StopStreaming() override;
  233. virtual void StopRecording() override;
  234. virtual bool StreamingActive() const override;
  235. virtual bool RecordingActive() const override;
  236. };
  237. static OBSData GetDataFromJsonFile(const char *jsonFile)
  238. {
  239. char fullPath[512];
  240. int ret = GetConfigPath(fullPath, sizeof(fullPath), jsonFile);
  241. if (ret > 0) {
  242. BPtr<char> jsonData = os_quick_read_utf8_file(fullPath);
  243. if (!!jsonData) {
  244. obs_data_t *data = obs_data_create_from_json(jsonData);
  245. OBSData dataRet(data);
  246. obs_data_release(data);
  247. return dataRet;
  248. }
  249. }
  250. return nullptr;
  251. }
  252. AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
  253. {
  254. const char *recType = config_get_string(main->Config(), "AdvOut",
  255. "RecType");
  256. const char *streamEncoder = config_get_string(main->Config(), "AdvOut",
  257. "Encoder");
  258. const char *recordEncoder = config_get_string(main->Config(), "AdvOut",
  259. "RecEncoder");
  260. ffmpegRecording = astrcmpi(recType, "FFmpeg") == 0;
  261. useStreamEncoder = astrcmpi(recordEncoder, "none") == 0;
  262. OBSData streamEncSettings = GetDataFromJsonFile(
  263. "obs-studio/basic/streamEncoder.json");
  264. OBSData recordEncSettings = GetDataFromJsonFile(
  265. "obs-studio/basic/recordEncoder.json");
  266. streamOutput = obs_output_create("rtmp_output", "adv_stream",
  267. nullptr, nullptr);
  268. if (!streamOutput)
  269. throw "Failed to create stream output (advanced output)";
  270. obs_output_release(streamOutput);
  271. if (ffmpegRecording) {
  272. fileOutput = obs_output_create("ffmpeg_output",
  273. "adv_ffmpeg_output", nullptr, nullptr);
  274. if (!fileOutput)
  275. throw "Failed to create recording FFmpeg output "
  276. "(advanced output)";
  277. obs_output_release(fileOutput);
  278. } else {
  279. fileOutput = obs_output_create("flv_output", "adv_file_output",
  280. nullptr, nullptr);
  281. if (!fileOutput)
  282. throw "Failed to create recording output "
  283. "(advanced output)";
  284. obs_output_release(fileOutput);
  285. if (!useStreamEncoder) {
  286. h264Recording = obs_video_encoder_create(recordEncoder,
  287. "recording_h264", recordEncSettings,
  288. nullptr);
  289. if (!h264Recording)
  290. throw "Failed to create recording h264 "
  291. "encoder (advanced output)";
  292. obs_encoder_release(h264Recording);
  293. }
  294. }
  295. h264Streaming = obs_video_encoder_create(streamEncoder,
  296. "streaming_h264", streamEncSettings, nullptr);
  297. if (!h264Streaming)
  298. throw "Failed to create streaming h264 encoder "
  299. "(advanced output)";
  300. obs_encoder_release(h264Streaming);
  301. for (int i = 0; i < 4; i++) {
  302. char name[9];
  303. sprintf(name, "adv_aac%d", i);
  304. aacTrack[i] = CreateAACEncoder(name, i);
  305. if (!aacTrack[i])
  306. throw "Failed to create audio encoder "
  307. "(advanced output)";
  308. }
  309. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  310. "start", OBSStartStreaming, this);
  311. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  312. "stop", OBSStopStreaming, this);
  313. signal_handler_connect(obs_output_get_signal_handler(fileOutput),
  314. "start", OBSStartRecording, this);
  315. signal_handler_connect(obs_output_get_signal_handler(fileOutput),
  316. "stop", OBSStopRecording, this);
  317. }
  318. void AdvancedOutput::UpdateStreamSettings()
  319. {
  320. bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut",
  321. "ApplyServiceSettings");
  322. OBSData settings = GetDataFromJsonFile(
  323. "obs-studio/basic/streamEncoder.json");
  324. if (applyServiceSettings)
  325. obs_service_apply_encoder_settings(main->GetService(),
  326. settings, nullptr);
  327. video_t *video = obs_get_video();
  328. enum video_format format = video_output_get_format(video);
  329. if (format != VIDEO_FORMAT_NV12 && format != VIDEO_FORMAT_I420)
  330. obs_encoder_set_preferred_video_format(h264Streaming,
  331. VIDEO_FORMAT_NV12);
  332. obs_encoder_update(h264Streaming, settings);
  333. }
  334. inline void AdvancedOutput::UpdateRecordingSettings()
  335. {
  336. OBSData settings = GetDataFromJsonFile(
  337. "obs-studio/basic/recordEncoder.json");
  338. obs_encoder_update(h264Recording, settings);
  339. }
  340. void AdvancedOutput::Update()
  341. {
  342. UpdateStreamSettings();
  343. if (!useStreamEncoder && !ffmpegRecording)
  344. UpdateRecordingSettings();
  345. UpdateAudioSettings();
  346. }
  347. inline void AdvancedOutput::SetupStreaming()
  348. {
  349. bool rescale = config_get_bool(main->Config(), "AdvOut",
  350. "Rescale");
  351. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  352. "RescaleRes");
  353. bool multitrack = config_get_bool(main->Config(), "AdvOut",
  354. "Multitrack");
  355. int trackIndex = config_get_int(main->Config(), "AdvOut",
  356. "TrackIndex");
  357. int trackCount = config_get_int(main->Config(), "AdvOut",
  358. "TrackCount");
  359. unsigned int cx = 0;
  360. unsigned int cy = 0;
  361. if (rescale && rescaleRes && *rescaleRes) {
  362. if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
  363. cx = 0;
  364. cy = 0;
  365. }
  366. }
  367. obs_encoder_set_scaled_size(h264Streaming, cx, cy);
  368. obs_encoder_set_video(h264Streaming, obs_get_video());
  369. obs_output_set_video_encoder(streamOutput, h264Streaming);
  370. if (multitrack) {
  371. int i = 0;
  372. for (; i < trackCount; i++)
  373. obs_output_set_audio_encoder(streamOutput, aacTrack[i],
  374. i);
  375. for (; i < 4; i++)
  376. obs_output_set_audio_encoder(streamOutput, nullptr, i);
  377. } else {
  378. obs_output_set_audio_encoder(streamOutput,
  379. aacTrack[trackIndex - 1], 0);
  380. }
  381. }
  382. inline void AdvancedOutput::SetupRecording()
  383. {
  384. const char *path = config_get_string(main->Config(), "AdvOut",
  385. "RecFilePath");
  386. bool rescale = config_get_bool(main->Config(), "AdvOut",
  387. "RecRescale");
  388. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  389. "RecRescaleRes");
  390. bool multitrack = config_get_bool(main->Config(), "AdvOut",
  391. "RecMultitrack");
  392. int trackIndex = config_get_int(main->Config(), "AdvOut",
  393. "RecTrackIndex");
  394. int trackCount = config_get_int(main->Config(), "AdvOut",
  395. "RecTrackCount");
  396. obs_data_t *settings = obs_data_create();
  397. unsigned int cx = 0;
  398. unsigned int cy = 0;
  399. if (useStreamEncoder) {
  400. obs_output_set_video_encoder(fileOutput, h264Streaming);
  401. } else {
  402. if (rescale && rescaleRes && *rescaleRes) {
  403. if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
  404. cx = 0;
  405. cy = 0;
  406. }
  407. }
  408. obs_encoder_set_scaled_size(h264Recording, cx, cy);
  409. obs_encoder_set_video(h264Recording, obs_get_video());
  410. obs_output_set_video_encoder(fileOutput, h264Recording);
  411. }
  412. if (multitrack) {
  413. int i = 0;
  414. for (; i < trackCount; i++)
  415. obs_output_set_audio_encoder(fileOutput, aacTrack[i],
  416. i);
  417. for (; i < 4; i++)
  418. obs_output_set_audio_encoder(fileOutput, nullptr, i);
  419. } else {
  420. obs_output_set_audio_encoder(fileOutput,
  421. aacTrack[trackIndex - 1], 0);
  422. }
  423. obs_data_set_string(settings, "path", path);
  424. obs_output_update(fileOutput, settings);
  425. obs_data_release(settings);
  426. }
  427. inline void AdvancedOutput::SetupFFmpeg()
  428. {
  429. const char *url = config_get_string(main->Config(), "AdvOut", "FFURL");
  430. int vBitrate = config_get_int(main->Config(), "AdvOut",
  431. "FFVBitrate");
  432. bool rescale = config_get_bool(main->Config(), "AdvOut",
  433. "FFRescale");
  434. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  435. "FFRescaleRes");
  436. const char *formatName = config_get_string(main->Config(), "AdvOut",
  437. "FFFormat");
  438. const char *mimeType = config_get_string(main->Config(), "AdvOut",
  439. "FFFormatMimeType");
  440. const char *vEncoder = config_get_string(main->Config(), "AdvOut",
  441. "FFVEncoder");
  442. int vEncoderId = config_get_int(main->Config(), "AdvOut",
  443. "FFVEncoderId");
  444. const char *vEncCustom = config_get_string(main->Config(), "AdvOut",
  445. "FFVCustom");
  446. int aBitrate = config_get_int(main->Config(), "AdvOut",
  447. "FFABitrate");
  448. int aTrack = config_get_int(main->Config(), "AdvOut",
  449. "FFAudioTrack");
  450. const char *aEncoder = config_get_string(main->Config(), "AdvOut",
  451. "FFAEncoder");
  452. int aEncoderId = config_get_int(main->Config(), "AdvOut",
  453. "FFAEncoderId");
  454. const char *aEncCustom = config_get_string(main->Config(), "AdvOut",
  455. "FFACustom");
  456. obs_data_t *settings = obs_data_create();
  457. obs_data_set_string(settings, "url", url);
  458. obs_data_set_string(settings, "format_name", formatName);
  459. obs_data_set_string(settings, "format_mime_type", mimeType);
  460. obs_data_set_int(settings, "video_bitrate", vBitrate);
  461. obs_data_set_string(settings, "video_encoder", vEncoder);
  462. obs_data_set_int(settings, "video_encoder_id", vEncoderId);
  463. obs_data_set_string(settings, "video_settings", vEncCustom);
  464. obs_data_set_int(settings, "audio_bitrate", aBitrate);
  465. obs_data_set_string(settings, "audio_encoder", aEncoder);
  466. obs_data_set_int(settings, "audio_encoder_id", aEncoderId);
  467. obs_data_set_string(settings, "audio_settings", aEncCustom);
  468. if (rescale && rescaleRes && *rescaleRes) {
  469. int width;
  470. int height;
  471. int val = sscanf(rescaleRes, "%dx%d", &width, &height);
  472. if (val == 2 && width && height) {
  473. obs_data_set_int(settings, "scale_width", width);
  474. obs_data_set_int(settings, "scale_height", height);
  475. }
  476. }
  477. obs_output_set_mixer(fileOutput, aTrack - 1);
  478. obs_output_set_media(fileOutput, obs_get_video(), obs_get_audio());
  479. obs_output_update(fileOutput, settings);
  480. obs_data_release(settings);
  481. }
  482. static inline void SetEncoderName(obs_encoder_t *encoder, const char *name,
  483. const char *defaultName)
  484. {
  485. obs_encoder_set_name(encoder, (name && *name) ? name : defaultName);
  486. }
  487. inline void AdvancedOutput::UpdateAudioSettings()
  488. {
  489. int track1Bitrate = config_get_uint(main->Config(), "AdvOut",
  490. "Track1Bitrate");
  491. int track2Bitrate = config_get_uint(main->Config(), "AdvOut",
  492. "Track2Bitrate");
  493. int track3Bitrate = config_get_uint(main->Config(), "AdvOut",
  494. "Track3Bitrate");
  495. int track4Bitrate = config_get_uint(main->Config(), "AdvOut",
  496. "Track4Bitrate");
  497. const char *name1 = config_get_string(main->Config(), "AdvOut",
  498. "Track1Name");
  499. const char *name2 = config_get_string(main->Config(), "AdvOut",
  500. "Track2Name");
  501. const char *name3 = config_get_string(main->Config(), "AdvOut",
  502. "Track3Name");
  503. const char *name4 = config_get_string(main->Config(), "AdvOut",
  504. "Track4Name");
  505. bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut",
  506. "ApplyServiceSettings");
  507. int streamTrackIndex = config_get_int(main->Config(), "AdvOut",
  508. "TrackIndex");
  509. obs_data_t *settings[4];
  510. for (size_t i = 0; i < 4; i++)
  511. settings[i] = obs_data_create();
  512. obs_data_set_int(settings[0], "bitrate", track1Bitrate);
  513. obs_data_set_int(settings[1], "bitrate", track2Bitrate);
  514. obs_data_set_int(settings[2], "bitrate", track3Bitrate);
  515. obs_data_set_int(settings[3], "bitrate", track4Bitrate);
  516. SetEncoderName(aacTrack[0], name1, "Track1");
  517. SetEncoderName(aacTrack[1], name2, "Track2");
  518. SetEncoderName(aacTrack[2], name3, "Track3");
  519. SetEncoderName(aacTrack[3], name4, "Track4");
  520. for (size_t i = 0; i < 4; i++) {
  521. if (applyServiceSettings && (int)(i + 1) == streamTrackIndex)
  522. obs_service_apply_encoder_settings(main->GetService(),
  523. nullptr, settings[i]);
  524. obs_encoder_update(aacTrack[i], settings[i]);
  525. obs_data_release(settings[i]);
  526. }
  527. }
  528. void AdvancedOutput::SetupOutputs()
  529. {
  530. obs_encoder_set_video(h264Streaming, obs_get_video());
  531. if (h264Recording)
  532. obs_encoder_set_video(h264Recording, obs_get_video());
  533. obs_encoder_set_audio(aacTrack[0], obs_get_audio());
  534. obs_encoder_set_audio(aacTrack[1], obs_get_audio());
  535. obs_encoder_set_audio(aacTrack[2], obs_get_audio());
  536. obs_encoder_set_audio(aacTrack[3], obs_get_audio());
  537. SetupStreaming();
  538. if (ffmpegRecording)
  539. SetupFFmpeg();
  540. else
  541. SetupRecording();
  542. }
  543. bool AdvancedOutput::StartStreaming(obs_service_t *service)
  544. {
  545. if (!useStreamEncoder ||
  546. (!ffmpegRecording && !obs_output_active(fileOutput))) {
  547. UpdateStreamSettings();
  548. }
  549. UpdateAudioSettings();
  550. if (!Active())
  551. SetupOutputs();
  552. obs_output_set_service(streamOutput, service);
  553. bool reconnect = config_get_bool(main->Config(), "AdvOut", "Reconnect");
  554. int retryDelay = config_get_int(main->Config(), "AdvOut", "RetryDelay");
  555. int maxRetries = config_get_int(main->Config(), "AdvOut", "MaxRetries");
  556. if (!reconnect)
  557. maxRetries = 0;
  558. obs_output_set_reconnect_settings(streamOutput, maxRetries,
  559. retryDelay);
  560. if (obs_output_start(streamOutput)) {
  561. activeRefs++;
  562. return true;
  563. }
  564. return false;
  565. }
  566. bool AdvancedOutput::StartRecording()
  567. {
  568. if (!useStreamEncoder) {
  569. if (!ffmpegRecording) {
  570. UpdateRecordingSettings();
  571. }
  572. } else if (!obs_output_active(streamOutput)) {
  573. UpdateStreamSettings();
  574. }
  575. UpdateAudioSettings();
  576. if (!Active())
  577. SetupOutputs();
  578. if (!ffmpegRecording) {
  579. const char *path = config_get_string(main->Config(),
  580. "AdvOut", "RecFilePath");
  581. os_dir_t *dir = path ? os_opendir(path) : nullptr;
  582. if (!dir) {
  583. QMessageBox::information(main,
  584. QTStr("Output.BadPath.Title"),
  585. QTStr("Output.BadPath.Text"));
  586. return false;
  587. }
  588. os_closedir(dir);
  589. string strPath;
  590. strPath += path;
  591. char lastChar = strPath.back();
  592. if (lastChar != '/' && lastChar != '\\')
  593. strPath += "/";
  594. strPath += GenerateTimeDateFilename("flv");
  595. obs_data_t *settings = obs_data_create();
  596. obs_data_set_string(settings, "path", strPath.c_str());
  597. obs_output_update(fileOutput, settings);
  598. obs_data_release(settings);
  599. }
  600. if (obs_output_start(fileOutput)) {
  601. activeRefs++;
  602. return true;
  603. }
  604. return false;
  605. }
  606. void AdvancedOutput::StopStreaming()
  607. {
  608. obs_output_stop(streamOutput);
  609. }
  610. void AdvancedOutput::StopRecording()
  611. {
  612. obs_output_stop(fileOutput);
  613. }
  614. bool AdvancedOutput::StreamingActive() const
  615. {
  616. return obs_output_active(streamOutput);
  617. }
  618. bool AdvancedOutput::RecordingActive() const
  619. {
  620. return obs_output_active(fileOutput);
  621. }
  622. /* ------------------------------------------------------------------------ */
  623. BasicOutputHandler *CreateSimpleOutputHandler(OBSBasic *main)
  624. {
  625. return new SimpleOutput(main);
  626. }
  627. BasicOutputHandler *CreateAdvancedOutputHandler(OBSBasic *main)
  628. {
  629. return new AdvancedOutput(main);
  630. }