New upstream version 26.1.0+dfsg1
This commit is contained in:
parent
040dcc3fc2
commit
013818c4af
594 changed files with 19576 additions and 4478 deletions
|
|
@ -20,8 +20,9 @@ set(obs-ffmpeg_config_HEADERS
|
|||
"${CMAKE_CURRENT_BINARY_DIR}/obs-ffmpeg-config.h")
|
||||
|
||||
set(obs-ffmpeg_HEADERS
|
||||
obs-ffmpeg-compat.h
|
||||
obs-ffmpeg-formats.h
|
||||
obs-ffmpeg-compat.h)
|
||||
obs-ffmpeg-mux.h)
|
||||
|
||||
set(obs-ffmpeg_SOURCES
|
||||
obs-ffmpeg.c
|
||||
|
|
@ -29,6 +30,7 @@ set(obs-ffmpeg_SOURCES
|
|||
obs-ffmpeg-nvenc.c
|
||||
obs-ffmpeg-output.c
|
||||
obs-ffmpeg-mux.c
|
||||
obs-ffmpeg-hls-mux.c
|
||||
obs-ffmpeg-source.c)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
FFmpegOutput="FFmpeg‐Ausgabe"
|
||||
FFmpegAAC="FFmpeg‐Standard‐AAC‐Encoder"
|
||||
FFmpegOpus="FFmpeg‐Opus‐Encoder"
|
||||
FFmpegOutput="FFmpeg-Ausgabe"
|
||||
FFmpegAAC="FFmpeg-Standard-AAC-Encoder"
|
||||
FFmpegOpus="FFmpeg-Opus-Encoder"
|
||||
Bitrate="Bitrate"
|
||||
MaxBitrate="Max. Bitrate"
|
||||
Preset="Voreinstellung"
|
||||
|
|
@ -9,9 +9,9 @@ RateControl="Qualitätsregulierungsmethode"
|
|||
KeyframeIntervalSec="Keyframeintervall in Sek. (0 = automatisch)"
|
||||
Lossless="Verlustfrei"
|
||||
|
||||
BFrames="Max. B‐Frames"
|
||||
BFrames="Max. B-Frames"
|
||||
|
||||
NVENC.Use2Pass="Two‐Pass‐Codierung verwenden"
|
||||
NVENC.Use2Pass="Two-Pass-Codierung verwenden"
|
||||
NVENC.Preset.default="Leistung"
|
||||
NVENC.Preset.hq="Qualität"
|
||||
NVENC.Preset.hp="Max. Leistung"
|
||||
|
|
@ -20,10 +20,10 @@ NVENC.Preset.ll="Niedrige Latenz"
|
|||
NVENC.Preset.llhq="Niedrige Latenz und Qualität"
|
||||
NVENC.Preset.llhp="Niedrige Latenz und Leistung"
|
||||
NVENC.LookAhead="Lookahead"
|
||||
NVENC.LookAhead.ToolTip="Aktiviert dynamische B‐Frames.\n\nWenn deaktiviert, wird der Encoder immer die Anzahl der B‐Frames verwenden, die in der Einstellung „Max. B‐Frames“ angegeben sind.\n\nWenn aktiviert, wird die visuelle Qualität erhöht, indem nur so viele B‐Frames bis zum Maximum verwendet werden, wie benötigt.\n(Resultiert in eine höhere GPU‐Nutzung.)"
|
||||
NVENC.LookAhead.ToolTip="Aktiviert dynamische B-Frames.\n\nWenn deaktiviert, wird der Encoder immer die Anzahl der B-Frames verwenden, die in der Einstellung „Max. B-Frames“ angegeben sind.\n\nWenn aktiviert, wird die visuelle Qualität erhöht, indem nur so viele B-Frames bis zum Maximum verwendet werden, wie benötigt.\n(Resultiert in eine höhere GPU-Nutzung.)"
|
||||
NVENC.PsychoVisualTuning="Psycho Visual Tuning"
|
||||
NVENC.PsychoVisualTuning.ToolTip="Aktiviert Encodereinstellungen, die die Verwendung der Bitrate für eine erhöhte wahrgenommene visuelle Qualität optimieren,\ninsbesondere in Situationen mit hoher Bewegung.\n(Resultiert in eine höhere GPU‐Nutzung.)"
|
||||
NVENC.CQLevel="CQ‐Level"
|
||||
NVENC.PsychoVisualTuning.ToolTip="Aktiviert Encodereinstellungen, die die Verwendung der Bitrate für eine erhöhte wahrgenommene visuelle Qualität optimieren,\ninsbesondere in Situationen mit hoher Bewegung.\n(Resultiert in eine höhere GPU-Nutzung.)"
|
||||
NVENC.CQLevel="CQ-Level"
|
||||
|
||||
FFmpegSource="Medienquelle"
|
||||
LocalFile="Lokale Datei"
|
||||
|
|
@ -37,7 +37,7 @@ Advanced="Erweitert"
|
|||
RestartWhenActivated="Wiedergabe bei Quellenaktivierung erneut starten"
|
||||
CloseFileWhenInactive="Datei schließen, wenn inaktiv"
|
||||
CloseFileWhenInactive.ToolTip="Schließt die Datei, wenn die Quelle im Stream oder in der Aufnahme nicht angezeigt wird.\nDies ermöglicht Änderungen an der Datei vorzunehmen,\nwas aber zu Reaktivierungsverzögerungen führen kann."
|
||||
ColorRange="YUV‐Farbbereich"
|
||||
ColorRange="YUV-Farbbereich"
|
||||
ColorRange.Auto="Automatisch"
|
||||
ColorRange.Partial="Teilweise"
|
||||
ColorRange.Full="Voll"
|
||||
|
|
@ -56,16 +56,16 @@ MediaFileFilter.AllFiles="Alle Dateien"
|
|||
ReplayBuffer="Wiederholungspuffer"
|
||||
ReplayBuffer.Save="Wiederholung speichern"
|
||||
|
||||
HelperProcessFailed="Der Aufnahme‐Helfer‐Prozess kann nicht gestartet werden. Überprüfen Sie, ob OBS‐Dateien nicht von einer Drittanbieter‐Antiviren‐/Sicherheitssoftware blockiert oder entfernt werden."
|
||||
HelperProcessFailed="Der Aufnahme-Helfer-Prozess kann nicht gestartet werden. Überprüfen Sie, ob OBS-Dateien nicht von einer Drittanbieter-Antiviren-/Sicherheitssoftware blockiert oder entfernt werden."
|
||||
UnableToWritePath="Kann nicht zu %1 schreiben. Vergewissern Sie sich, dass Sie einen Aufnahmepfad verwenden, für den Ihr Benutzerkonto Schreibrechte hat und dass genügend Speicherplatz zur Verfügung steht."
|
||||
WarnWindowsDefender="Wenn Windows‐10‐Ransomware‐Schutz aktiviert ist, kann dies auch den Fehler auslösen. Versuchen Sie, den überwachten Ordnerzugriff in „Windows‐Sicherheit“ → „Viren‐ & Bedrohungsschutz“ auszuschalten."
|
||||
WarnWindowsDefender="Wenn Windows-10-Ransomware-Schutz aktiviert ist, kann dies auch den Fehler verursachen. Versuchen Sie, den überwachten Ordnerzugriff in Windows-Sicherheit → Viren- & Bedrohungsschutz auszuschalten."
|
||||
|
||||
NVENC.Error="Fehler beim Öffnen des NVENC‐Codecs: %1"
|
||||
NVENC.Error="Fehler beim Öffnen des NVENC-Codecs: %1"
|
||||
NVENC.GenericError="Überprüfen Sie, ob Ihre Grafiktreiber aktuell sind. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet."
|
||||
NVENC.BadGPUIndex="Sie haben die GPU %1 in Ihren Ausgabeencodereinstellungen ausgewählt. Setzen Sie diesen Wert wieder auf 0 und versuchen Sie es erneut."
|
||||
NVENC.OutdatedDriver="Ihr aktueller Grafikkartentreiber unterstützt diese NVENC‐Version nicht. Bitte aktualisieren Sie Ihre Treiber."
|
||||
NVENC.UnsupportedDevice="NVENC‐Fehler: Nicht unterstütztes Gerät. Überprüfen Sie, ob Ihre Grafikkarte NVENC unterstützt und Ihre Treiber aktuell sind."
|
||||
NVENC.TooManySessions="NVENC‐Fehler: Zu viele gleichzeitige Sitzungen. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet."
|
||||
NVENC.OutdatedDriver="Ihr aktueller Grafikkartentreiber unterstützt diese NVENC-Version nicht. Bitte aktualisieren Sie Ihre Treiber."
|
||||
NVENC.UnsupportedDevice="NVENC-Fehler: Nicht unterstütztes Gerät. Überprüfen Sie, ob Ihre Grafikkarte NVENC unterstützt und Ihre Treiber aktuell sind."
|
||||
NVENC.TooManySessions="NVENC-Fehler: Zu viele gleichzeitige Sitzungen. Versuchen Sie, andere Aufnahmesoftware wie NVIDIA Shadowplay oder Windows 10 Game DVR zu schließen, welche NVENC möglicherweise verwendet."
|
||||
NVENC.CheckDrivers="Bitte überprüfen Sie, ob Ihre Grafiktreiber aktuell sind."
|
||||
|
||||
ReconnectDelayTime="Wiederverbindungsverzögerung"
|
||||
|
|
|
|||
|
|
@ -2,14 +2,22 @@ FFmpegOutput="Έξοδος FFmpeg"
|
|||
FFmpegAAC="FFmpeg προεπιλεγμένος κωδικοποιητής AAC"
|
||||
FFmpegOpus="FFmpeg Opus κωδικοποιητής"
|
||||
Bitrate="Ρυθμός μετάδοσης bit"
|
||||
MaxBitrate="Μέγιστος ρυθμός μετάδοσης bit"
|
||||
Preset="Προκαθορισμένο στυλ"
|
||||
Profile="Προφίλ"
|
||||
RateControl="Έλεγχος ρυθμού"
|
||||
KeyframeIntervalSec="Συχνότητα Καρέ-Κλειδιού (δευτερόλεπτα, 0=αυτόματο)"
|
||||
Lossless="Χωρίς απώλειες"
|
||||
|
||||
|
||||
NVENC.Use2Pass="Χρήση κωδικοποίησης δύο περασμάτων"
|
||||
NVENC.Preset.default="Επιδόσεις"
|
||||
NVENC.Preset.hq="Ποιότητα"
|
||||
NVENC.Preset.hp="Μέγιστες Επιδόσεις"
|
||||
NVENC.Preset.mq="Μέγιστη Ποιότητα"
|
||||
NVENC.Preset.ll="Χαμηλή Καθυστέρηση"
|
||||
NVENC.Preset.llhq="Ποιότητα Χαμηλής Καθυστέρησης"
|
||||
NVENC.Preset.llhp="Απόδοση Χαμηλής Καθυστέρησης"
|
||||
|
||||
FFmpegSource="Πηγή Πολυμέσων"
|
||||
LocalFile="Τοπικό αρχείο"
|
||||
|
|
@ -17,6 +25,7 @@ Looping="Επανάληψη"
|
|||
Input="Είσοδος"
|
||||
InputFormat="Μορφή Εισόδου"
|
||||
HardwareDecode="Χρήση αποκωδικοποίησης υλικού όταν είναι διαθέσιμη"
|
||||
ClearOnMediaEnd="Μη δείχνεις τίποτα όταν τελειώνει η αναπαραγωγή"
|
||||
Advanced="Σύνθετες επιλογές"
|
||||
RestartWhenActivated="Επανεκκίνηση της αναπαραγωγής όταν η πηγή γίνεται ξανά ενεργή"
|
||||
CloseFileWhenInactive="Κλείσιμο του αρχείου όταν η πηγή είναι ανενεργή"
|
||||
|
|
@ -25,7 +34,12 @@ ColorRange="Χώρος Χρωμάτων YUV"
|
|||
ColorRange.Auto="Αυτόματο"
|
||||
ColorRange.Partial="Μερικός"
|
||||
ColorRange.Full="Πλήρης"
|
||||
RestartMedia="Επανέναρξη"
|
||||
SpeedPercentage="Ταχύτητα"
|
||||
Seekable="Παρεχόμενη"
|
||||
Play="Αναπαραγωγή"
|
||||
Pause="Παύση"
|
||||
Stop="Διακοπή"
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Όλα τα αρχεία πολυμέσων"
|
||||
MediaFileFilter.VideoFiles="Αρχεία Βίντεο"
|
||||
|
|
@ -38,5 +52,11 @@ ReplayBuffer.Save="Αποθήκευση Replay"
|
|||
HelperProcessFailed="Αδυναμία έναρξης τού βοηθού της διαδικασίας εγγραφής. Ελέγξτε ότι τα αρχεία OBS δεν έχουν αποκλειστεί η καταργηθεί από ένα τρίτο antivirus / λογισμικό ασφαλείας."
|
||||
UnableToWritePath="Αδυναμία εγγραφής %1. Βεβαιωθείτε ότι χρησιμοποιείτε μια διαδρομή εγγραφής που επιτρέπεται για εγγραφή τού λογαριασμού χρήστη και ότι υπάρχει επαρκής χώρος στον σκληρό δίσκο."
|
||||
|
||||
NVENC.GenericError="Βεβαιωθείτε ότι οι οδηγοί βίντεο είναι ενημερωμένοι. Δοκιμάστε να κλείσετε άλλα λογισμικά βιντεοσκόπησης που μπορεί να χρησιμοποιούν το λογισμικό NVENC όπως το NVIDIA Shadowplay ή το Windows 10 Game DVR."
|
||||
NVENC.BadGPUIndex="'Έχετε επιλέξει τη συσκευή GPU %1 στις ρυθμίσεις του αποκωδικοποιητή εξόδου. Αλλάξτε τη ρύθμιση στο 0 και ξαναδοκιμάστε."
|
||||
NVENC.OutdatedDriver="Ο τρέχων οδηγός της κάρτας βίντεο δεν υποστηρίζει αυτή την έκδοση του λογισμικού NVENC, παρακαλώ ενημερώστε τους οδηγούς σας."
|
||||
NVENC.UnsupportedDevice="Σφάλμα NVENC: Μη υποστηριζόμενη συσκευή. Ελέγξτε εάν η κάρτα γραφικών σας υποστηρίζει το λογισμικό NVENC και ότι οι οδηγοί της συσκευής είναι ενημερωμένοι."
|
||||
NVENC.TooManySessions="Σφάλμα NVENC: Πάρα πολλές ταυτόχρονες χρήσεις. Δοκιμάστε να κλείσετε άλλα λογισμικά βιντεοσκόπησης που μπορεί να χρησιμοποιούν το λογισμικό NVENC όπως το NVIDIA Shadowplay ή το Windows 10 Game DVR."
|
||||
NVENC.CheckDrivers="Παρακαλώ βεβαιωθείτε ότι οι οδηγοί βίντεο είναι ενημερωμένοι."
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ FFmpegOpus="اپوس FFmpeg تخمین"
|
|||
Bitrate="نرخ بیت"
|
||||
MaxBitrate="حداکثر میزان نرخ بیت"
|
||||
Preset="پیش فرض"
|
||||
Profile="پروفایل"
|
||||
RateControl="کنترل نرخ"
|
||||
KeyframeIntervalSec="فاصله Keyframe (ثانیه 0 = خودکار)"
|
||||
Lossless="بدون تلف"
|
||||
|
|
@ -19,15 +20,33 @@ NVENC.Preset.ll="زمان تاخیر کم"
|
|||
NVENC.Preset.llhq="کیفیت پایین و زمان تاخیر"
|
||||
NVENC.Preset.llhp="زمان تاخیر کم عملکرد"
|
||||
NVENC.LookAhead="پیش رو نگاه"
|
||||
NVENC.LookAhead.ToolTip="فریم های B پویا را فعال می کند.\n\nاگر غیرفعال باشد، رمزگذار همیشه از تعداد فریم های B مشخص شده در تنظیمات \"حداکثر فریم B\" استفاده خواهد کرد.\n\nدر صورت فعال بودن، فقط با استفاده از تعداد زیادی کیفیت بصری فریم B حداکثر افزایش می یابد،\n مقدار استفاده از گرافیک افزایش می یابد."
|
||||
NVENC.PsychoVisualTuning="تنظیم بصری روانی"
|
||||
NVENC.PsychoVisualTuning.ToolTip="تنظیمات رمزگذار را که بهینه سازی استفاده از میزان بیت برای افزایش کیفیت بصری درک شده را امکان پذیر می کند، \nخصوصاً در شرایط با حرکت بالا، با استفاده بیشتر از گرافیک."
|
||||
NVENC.CQLevel="سطح تدریج ثابت"
|
||||
|
||||
FFmpegSource="منبع رسانه"
|
||||
LocalFile="فایل محلی"
|
||||
Looping="چرخه"
|
||||
Input="ورودی"
|
||||
InputFormat="فرمت های ورودی"
|
||||
BufferingMB="بافر شبکه"
|
||||
HardwareDecode="در صورت وجود از رمزگشایی سخت افزاری استفاده کنید"
|
||||
ClearOnMediaEnd="با پایان پخش، چیزی نشان داده نشود"
|
||||
Advanced="پیشرفته"
|
||||
RestartWhenActivated="با فعال شدن منبع پخش را دوباره شروع کنید"
|
||||
CloseFileWhenInactive="بستن پرونده در صورت غیرفعال بودن"
|
||||
CloseFileWhenInactive.ToolTip="وقتی منبع در جریان نمایش داده نمی شود یا\n ضبط نمی شود، پرونده را می بندد. این اجازه می دهد تا پرونده هنگام فعال نبودن منبع تغییر کند، \n اما ممکن است هنگام فعال شدن مجدد منبع، تأخیر در شروع وجود داشته باشد."
|
||||
ColorRange="فضای رنگی YUV"
|
||||
ColorRange.Auto="خودکار"
|
||||
ColorRange.Partial="جزئی"
|
||||
ColorRange.Full="کامل"
|
||||
RestartMedia="اجرا مجدد"
|
||||
SpeedPercentage="سرعت"
|
||||
Seekable="جستجوگر"
|
||||
Play="پخش"
|
||||
Pause="مکث"
|
||||
Stop="توقف"
|
||||
|
||||
MediaFileFilter.AllMediaFiles="تمامی فایل های رسانه"
|
||||
MediaFileFilter.VideoFiles="فایلهای ویدئویی"
|
||||
|
|
@ -37,6 +56,17 @@ MediaFileFilter.AllFiles="همهی فایل ها"
|
|||
ReplayBuffer="پخش مجدد بافر"
|
||||
ReplayBuffer.Save="ذخیره پخش مجدد"
|
||||
|
||||
HelperProcessFailed="فرآیند راهنمای ضبط شروع نمی شود. بررسی کنید که فایلهای OBS توسط هیچ یک از آنتی ویروس ها/نرم افزارهای امنیتی شخص ثالث مسدود یا حذف نشده باشند."
|
||||
UnableToWritePath="نوشتن در%1 امکان پذیر نیست. اطمینان حاصل کنید که از یک مسیر ضبط استفاده می کنید که حساب کاربری شما مجاز به نوشتن آن است و فضای دیسک کافی وجود دارد."
|
||||
WarnWindowsDefender="اگر محافظت در برابر باج افزار ویندوز 10 فعال باشد نیز می تواند باعث این خطا شود. دسترسی به پوشه کنترل شده را در امنیت ویندوز/تنظیمات محافظت در برابر تهدید خاموش کنید."
|
||||
|
||||
NVENC.Error="کدک NVENC باز نشد: %1"
|
||||
NVENC.GenericError="بررسی کنید که درایورهای ویدیویی شما به روز هستند. سایر نرم افزارهای ضبط را که ممکن است از NVENC مانند NVIDIA Shadowplay یا DVR بازی Windows 10 استفاده کنند، ببندید."
|
||||
NVENC.BadGPUIndex="شما گرافیک %1 را در تنظیمات رمزگذار خروجی خود انتخاب کرده اید. دوباره روی 0 تنظیم کنید و امتحان کنید."
|
||||
NVENC.OutdatedDriver="درایور کارت ویدیویی فعلی شما از این نسخه NVENC پشتیبانی نمی کند، لطفاً درایورهای خود را به روز کنید."
|
||||
NVENC.UnsupportedDevice="خطای NVENC: دستگاه پشتیبانی نمی شود. بررسی کنید کارت ویدیوی شما از NVENC پشتیبانی می کند و آیا درایورها به روز هستند."
|
||||
NVENC.TooManySessions="خطای NVENC: جلسات همزمان بسیار زیاد است. سایر نرم افزارهای ضبط را که ممکن است از NVENC مانند NVIDIA Shadowplay یا DVR بازی Windows 10 استفاده کنند، ببندید."
|
||||
NVENC.CheckDrivers="لطفاً به روز بودن درایورهای ویدیویی خود را بررسی کنید."
|
||||
|
||||
ReconnectDelayTime="تأخیر اتصال دوباره"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,13 +9,20 @@ Lossless="Lossless"
|
|||
|
||||
|
||||
NVENC.Use2Pass="Gamitin ang Two-Pass Encoding"
|
||||
NVENC.Preset.hq="Kalidad"
|
||||
NVENC.Preset.hp="Pinakamalakas na Pagganap"
|
||||
NVENC.Preset.mq="Pinakamalakas na Kalidad"
|
||||
NVENC.Preset.ll="Mababa na Latency"
|
||||
NVENC.Preset.llhq="Mababang-Latency na Kalidad"
|
||||
NVENC.Preset.llhp="Mababang-Latency na Pagganap"
|
||||
NVENC.CQLevel="CQ na Antas"
|
||||
|
||||
FFmpegSource="Pagkunan ng Media"
|
||||
LocalFile="Ang File na lokal"
|
||||
Looping="I-Loop"
|
||||
Input="Ang Input"
|
||||
InputFormat="Ang Format ng Input"
|
||||
BufferingMB="Pag-buffer ng Network"
|
||||
HardwareDecode="Gamitin ang hardware decoding kapag magagamit"
|
||||
Advanced="I-Advanced"
|
||||
RestartWhenActivated="Simulan mulang ang playback kapag aktibo ang pinagmulan"
|
||||
|
|
@ -43,5 +50,8 @@ ReplayBuffer.Save="I-Save ang Replay"
|
|||
HelperProcessFailed="Hindi pwedeng simulan ang pag proseso ng recording helper. Tingan kung OBS file ay hindi hinarangan o tinanggal ng anumang 3rd part antivirus / security software."
|
||||
UnableToWritePath="Hindi pwedeng sumulat sa %1. Siguraduhin na gamit ang recording path kung saan ang user account mo ay tanggap ang pagsulat at mayroon sapat na espasyo sa disk."
|
||||
|
||||
NVENC.OutdatedDriver="Ang iyong kasalakuyang video card driver ay hindi sinu-suporta ang itong NVENC na bersyon, mangyaring i-update ang iyong drivers."
|
||||
NVENC.UnsupportedDevice="Pagkakamali ng NVENC: Hindi supportadong aparato. Tignan mo ang iyong video card kung sinu-suporta nila ang NVENC at kung yung drivers ay bago."
|
||||
NVENC.CheckDrivers="Mangyaring tignan mo ang iyong video drivers kung ay bago sila."
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Looping="Berulang"
|
|||
Input="Masukan"
|
||||
InputFormat="Format Masukan"
|
||||
BufferingMB="Buffering Jaringan"
|
||||
HardwareDecode="Gunakan dekoder hardware jika tersedia"
|
||||
HardwareDecode="Gunakan dekoder perangkat keras jika tersedia"
|
||||
ClearOnMediaEnd="Tidak muncul apapun saat pemutaran berakhir"
|
||||
Advanced="Tingkat lanjut"
|
||||
RestartWhenActivated="Mulai ulang pemutaran ketika sumber sudah aktif"
|
||||
|
|
|
|||
53
plugins/obs-ffmpeg/data/locale/kab-KAB.ini
Normal file
53
plugins/obs-ffmpeg/data/locale/kab-KAB.ini
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
FFmpegOutput="Tuffɣa n FFmpeg"
|
||||
FFmpegAAC="Asettengal n lexṣas AAC n FFmpeg"
|
||||
FFmpegOpus="Asettengal Opus n FFmpeg"
|
||||
Bitrate="Aktum"
|
||||
MaxBitrate="Aktum afellay"
|
||||
Preset="Aseɣwer uzwir"
|
||||
Profile="Amaɣnu"
|
||||
RateControl="Asenqed n uktum"
|
||||
KeyframeIntervalSec="Azilal n yikataren yufraren (tasinin, 0=awurman)"
|
||||
Lossless="War asṛuḥu"
|
||||
|
||||
BFrames="Amḍan afellay n yikataren B"
|
||||
|
||||
NVENC.Use2Pass="Seqdec asettengel n sin isuka"
|
||||
NVENC.Preset.default="Tamellit"
|
||||
NVENC.Preset.hq="Taɣara"
|
||||
NVENC.Preset.hp="Tamellit tafellayt"
|
||||
NVENC.Preset.mq="Taɣara tafellayt"
|
||||
NVENC.CQLevel="Aswir CQ"
|
||||
|
||||
FFmpegSource="Aɣbalu amidya"
|
||||
LocalFile="Afaylu adigan"
|
||||
Looping="Tineddict"
|
||||
Input="Anekcum"
|
||||
InputFormat="Amasal n unekcum"
|
||||
BufferingMB="Ajmaɛ di tkatut n uḥraz n uzeḍḍa"
|
||||
HardwareDecode="Seqdec amakkas n usettengel n warrum ma yewjed"
|
||||
ClearOnMediaEnd="Ur beqqeḍ acemma mi ara tfak tɣuri"
|
||||
Advanced="Anaẓi"
|
||||
RestartWhenActivated="Kemmel si tazwara ticki iqel uɣbalu-agi d urmid"
|
||||
CloseFileWhenInactive="Mdel afaylu ticki ur yermid ara"
|
||||
ColorRange="Tagrumma n yini YUV"
|
||||
ColorRange.Auto="Awurman"
|
||||
ColorRange.Partial="Abruyan"
|
||||
ColorRange.Full="Ummid"
|
||||
RestartMedia="Ales asekker"
|
||||
SpeedPercentage="Arured"
|
||||
Play="Taɣuri"
|
||||
Pause="Bedd"
|
||||
Stop="Seḥbes"
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Akk ifuyla imidyaten"
|
||||
MediaFileFilter.VideoFiles="Ifuyla n uvidyu"
|
||||
MediaFileFilter.AudioFiles="Ifuyla imeslawen"
|
||||
MediaFileFilter.AllFiles="Akk ifuyla"
|
||||
|
||||
ReplayBuffer="Tallunt n weḥraz n tulsa n tɣuri"
|
||||
ReplayBuffer.Save="Sekles tulsa n tɣuri"
|
||||
|
||||
|
||||
|
||||
ReconnectDelayTime="Amenḍar n tulsa n tɣuri"
|
||||
|
||||
|
|
@ -63,8 +63,8 @@ WarnWindowsDefender="윈도우 10에서 제공하는 랜섬웨어 보호 기능
|
|||
NVENC.Error="NVENC 코덱을 여는데 실패함: %1"
|
||||
NVENC.GenericError="드라이버가 최신 버전인지 확인하세요. NVIDIA Shadowplay 혹은 Windows 10 게임 바 캡처 기능과 같이 NVENC를 사용하고 있는 다른 녹화 프로그램을 꺼보세요."
|
||||
NVENC.BadGPUIndex="출력 설정 내 인코더 항목에서 GPU %1 (을)를 지정했습니다. 이 항목을 0으로 되돌린 다음 다시 시도해보세요."
|
||||
NVENC.OutdatedDriver="현재 사용하고 있는 비디오 카드 드라이버가 이 NVENC 버전을 지원하지 않습니다. 드라이버를 판올림하여 주세요."
|
||||
NVENC.UnsupportedDevice="NVENC 오류: 지원하지 않는 장치입니다. 비디오 카드가 NVENC를 지원하고 있고 최신 버전으로 판올림 되어 있는지 확인하여 주세요."
|
||||
NVENC.OutdatedDriver="현재 사용하고 있는 비디오 카드 드라이버가 이 NVENC 버전을 지원하지 않습니다. 드라이버를 업데이트 해주세요."
|
||||
NVENC.UnsupportedDevice="NVENC 오류: 지원하지 않는 장치입니다. 비디오 카드가 NVENC를 지원하고 있고 최신 버전으로 업데이트되어 있는지 확인해주세요."
|
||||
NVENC.TooManySessions="NVENC 오류: 너무 많은 세션을 동시에 처리하고 있습니다. NVIDIA Shadowplay 혹은 Windows 10 게임 바 캡처 기능과 같이 NVENC를 사용하고 있는 다른 녹화 프로그램을 꺼보세요."
|
||||
NVENC.CheckDrivers="사용 중인 그래픽 드라이버가 최신 버전인지 확인하여 주세요."
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ FFmpegOpus="FFmpeg Opus enkoder"
|
|||
Bitrate="Bitrate"
|
||||
MaxBitrate="Maks bitrate"
|
||||
Preset="Forhåndsinnstilling"
|
||||
Profile="Profil"
|
||||
RateControl="Hastighetskontroll"
|
||||
KeyframeIntervalSec="Nøkkelbildeintervall (sekunder, 0 = automatisk)"
|
||||
Lossless="Tapsfri"
|
||||
|
|
@ -67,4 +68,5 @@ NVENC.UnsupportedDevice="NVENC Error: Ustøttet enhet. Sjekk at videokortet ditt
|
|||
NVENC.TooManySessions="NVENC Feil: For mange samtidige økter. Prøv å lukke annen opptaksprogramvare at bruker kanskje NVENC, som NVIDIA Shadowplay eller Windows 10 Game DVR."
|
||||
NVENC.CheckDrivers="Vennligst sjekk at videosjåførene dine er oppdatert."
|
||||
|
||||
ReconnectDelayTime="Gjenoppkoblingsforsinkelse"
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ NVENC.PsychoVisualTuning.ToolTip="Permite configurações do codificador que oti
|
|||
NVENC.CQLevel="Nível de CQ"
|
||||
|
||||
FFmpegSource="Fonte de mídia"
|
||||
LocalFile="Arquivo Local"
|
||||
LocalFile="Arquivo local"
|
||||
Looping="Loop"
|
||||
Input="Entrada"
|
||||
InputFormat="Formato de entrada"
|
||||
|
|
@ -37,7 +37,7 @@ Advanced="Avançado"
|
|||
RestartWhenActivated="Reiniciar reprodução quando a fonte se tornar ativa"
|
||||
CloseFileWhenInactive="Fechar arquivo quando inativo"
|
||||
CloseFileWhenInactive.ToolTip="Fechar o arquivo quando a fonte não estiver sendo exibida na transmissão\n ou gravação. Isto permite alterar o arquivo quando a fonte não está ativa,\nmas pode ter algum atraso de inicialização quando a fonte for reativada."
|
||||
ColorRange="Intervalo de Cores YUV"
|
||||
ColorRange="Intervalo de cores YUV"
|
||||
ColorRange.Auto="Auto"
|
||||
ColorRange.Partial="Parcial"
|
||||
ColorRange.Full="Completo"
|
||||
|
|
@ -48,10 +48,10 @@ Play="Iniciar"
|
|||
Pause="Pausar"
|
||||
Stop="Parar"
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Todos Arquivos de Mídia"
|
||||
MediaFileFilter.AllMediaFiles="Todos os arquivos de mídia"
|
||||
MediaFileFilter.VideoFiles="Arquivos de Vídeo"
|
||||
MediaFileFilter.AudioFiles="Arquivos de Áudio"
|
||||
MediaFileFilter.AllFiles="Todos os Arquivos"
|
||||
MediaFileFilter.AllFiles="Todos os arquivos"
|
||||
|
||||
ReplayBuffer="Buffer do Replay"
|
||||
ReplayBuffer.Save="Salvar Replay"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ FFmpegOpus="FFmpeg Opus Encoder"
|
|||
Bitrate="Bitrate"
|
||||
MaxBitrate="Bitrate Máximo"
|
||||
Preset="Predefinição"
|
||||
Profile="Perfil"
|
||||
RateControl="Controle de Taxa"
|
||||
KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)"
|
||||
Lossless="Sem perdas"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RateControl="Controlul ratei"
|
|||
KeyframeIntervalSec="Interval de cadre cheie (secunde, 0=auto)"
|
||||
Lossless="Fără pierderi"
|
||||
|
||||
BFrames="Max B-frames"
|
||||
BFrames="Cadre B maxime"
|
||||
|
||||
NVENC.Use2Pass="Folosește codificarea în doi pași"
|
||||
NVENC.Preset.default="Performanță"
|
||||
|
|
@ -19,9 +19,9 @@ NVENC.Preset.mq="Calitate maximă"
|
|||
NVENC.Preset.ll="Latență redusă"
|
||||
NVENC.Preset.llhq="Calitate cu latență redusă"
|
||||
NVENC.Preset.llhp="Performanță cu latență redusă"
|
||||
NVENC.LookAhead="Privire"
|
||||
NVENC.LookAhead.ToolTip="Activează B-frames dinamic.\n\nDacă este dezactivat, encoder-ul va utiliza întotdeauna numărul de B-frames specificat în setările 'Max B-frames'.\n\nDacă este activat, va crește calitatea vizuală utilizând doar cât de multe cadre B sunt necesare, până la maximum,\nla costul unei utilizări crescute a GPU."
|
||||
NVENC.PsychoVisualTuning="Aranjare vizuală Psycho"
|
||||
NVENC.LookAhead="Look-ahead"
|
||||
NVENC.LookAhead.ToolTip="Activează cadre B dinamice.\n\nDacă este dezactivat, codificatorul va folosi întotdeauna numărul de cadre B specificat în setarea „Cadre B maxime”.\n\nDacă este activat, va crește calitatea vizuală folosind doar cât de multe cadre B sunt necesare, până la maximum,\ncu costul utilizării crescute a GPU-ului."
|
||||
NVENC.PsychoVisualTuning="Psycho Visual Tuning"
|
||||
NVENC.PsychoVisualTuning.ToolTip="Activează setările de codificare care optimizează utilizarea ratei de biți pentru creșterea calității vizuale percepute,\nîn special în situații cu mișcare mare, cu prețul unei utilizări mai mari a GPU."
|
||||
NVENC.CQLevel="Nivel CQ"
|
||||
|
||||
|
|
@ -31,21 +31,21 @@ Looping="Redă în buclă"
|
|||
Input="Input"
|
||||
InputFormat="Formatul inputului"
|
||||
BufferingMB="Buffer Rețea"
|
||||
HardwareDecode="Folosește decodarea hardware când este disponibilă"
|
||||
HardwareDecode="Folosește decodificarea hardware când este disponibilă"
|
||||
ClearOnMediaEnd="Nu afișa nimic la terminarea redării"
|
||||
Advanced="Avansat"
|
||||
RestartWhenActivated="Repornește redarea când sursa devine activă"
|
||||
CloseFileWhenInactive="Închide fișierul când este inactiv"
|
||||
CloseFileWhenInactive.ToolTip="Închide fișierul atunci când sursa nu este afișată pe transmisiune sau\nînregistrare. Acest lucru permite fișierului să fie schimbat în momentul în care sursa nu este activă,\nînsă poate exista o întârziere la pornire în momentul reactivării sursei."
|
||||
CloseFileWhenInactive.ToolTip="Închide fișierul atunci când sursa nu este afișată pe transmisiune sau înregistrare.\nAcest lucru permite fișierului să fie schimbat în momentul în care sursa nu este\nactivă, însă poate exista o întârziere la pornire în momentul reactivării sursei."
|
||||
ColorRange="Gamă de culori YUV"
|
||||
ColorRange.Auto="Automată"
|
||||
ColorRange.Partial="Parțială"
|
||||
ColorRange.Full="Completă"
|
||||
RestartMedia="Repornește"
|
||||
SpeedPercentage="Viteză"
|
||||
Seekable="Vizulizare"
|
||||
Seekable="Navigabil"
|
||||
Play="Redare"
|
||||
Pause="Pauzează"
|
||||
Pause="Pune pe pauză"
|
||||
Stop="Stop"
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Toate fișierele media"
|
||||
|
|
@ -53,17 +53,17 @@ MediaFileFilter.VideoFiles="Fișiere video"
|
|||
MediaFileFilter.AudioFiles="Fișiere audio"
|
||||
MediaFileFilter.AllFiles="Toate fișierele"
|
||||
|
||||
ReplayBuffer="Reluare Buffer"
|
||||
ReplayBuffer="Buffer de reluări"
|
||||
ReplayBuffer.Save="Salvează reluarea"
|
||||
|
||||
HelperProcessFailed="Nu se poate porni procesul ajutător de înregistrare. Verifică dacă fișierele OBS nu au fost blocate sau eliminate de orice software terț antivirus / de securitate."
|
||||
UnableToWritePath="Imposibil de scris la %1. Asigurați-vă că folosiți o cale de înregistrare pe care contul dvs. de utilizator poate să o scrie și că există suficient spațiu pe disc."
|
||||
UnableToWritePath="Nu se poate scrie în %1. Asigură-te că folosești o cale de înregistrare în care contul tău de utilizator are permisiunea de a scrie și că există suficient spațiu pe disc."
|
||||
WarnWindowsDefender="Dacă este activată protecţia Ransomware Windows 10 poate cauza şi această eroare. Încercați să dezactivați accesul la dosarele controlate în setările de securitate / Virus și protecție împotriva amenințării."
|
||||
|
||||
NVENC.Error="Deschiderea codecului NVENC a eșuat: %1"
|
||||
NVENC.GenericError="Verifică dacă driverele video sunt actualizate. Încercați să închideți alte programe de înregistrare care ar putea utiliza NVENC, cum ar fi NVIDIA Shadowplay sau Windows 10 Game DVR."
|
||||
NVENC.BadGPUIndex="Ai selectat GPU-ul %1 în setările codificatorului de output. Setează acest lucru înapoi la 0 și încearcă din nou."
|
||||
NVENC.OutdatedDriver="Driver-ul dvs. actual de pe cardul video nu acceptă această versiune NVENC, vă rugăm să vă actualizați driverele."
|
||||
NVENC.OutdatedDriver="Driverul actual al plăcii tale video nu suportă această versiune NVENC, te rugăm să actualizezi driverele."
|
||||
NVENC.UnsupportedDevice="Eroare NVENC. Dispozitivul nu este acceptat. Verificați dacă cardul video suportă NVENC și dacă driverele sunt actualizate."
|
||||
NVENC.TooManySessions="Eroare NVENC: Prea multe sesiuni concurente. Încercați să închideți alte programe de înregistrare care ar putea folosi NVENC, cum ar fi NVIDIA Shadowplay sau Windows 10 Game DVR."
|
||||
NVENC.CheckDrivers="Te rugăm să verifici dacă driverele video sunt actualizate."
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ FFmpegOpus="Kodirnik Opus FFmpeg"
|
|||
Bitrate="Bitna hitrost"
|
||||
MaxBitrate="Največja bitna hitrost"
|
||||
Preset="Prednastavitev"
|
||||
Profile="Profil"
|
||||
RateControl="Nadzor hitrosti"
|
||||
KeyframeIntervalSec="Razmik med ključnimi sličicami (ssekunde, 0=samodejno)"
|
||||
Lossless="Brezizgubno"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Looping="Upprepa"
|
|||
Input="Infoga"
|
||||
InputFormat="Inmatningsformat"
|
||||
BufferingMB="Nätverksbuffring"
|
||||
HardwareDecode="Använda hårdvareavkodning när tillgängligt"
|
||||
HardwareDecode="Använd hårdvaruavkodning när det är tillgängligt"
|
||||
ClearOnMediaEnd="Visa ingenting när uppspelningen slutar"
|
||||
Advanced="Avancerat"
|
||||
RestartWhenActivated="Starta om uppspelning när källa blir aktiv"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
FFmpegOutput="FFmpeg đầu ra"
|
||||
FFmpegAAC="FFmpeg AAC Encoder mặc định"
|
||||
FFmpegOpus="Bộ mã hóa FFmpeg Opus"
|
||||
Bitrate="Bitrate"
|
||||
MaxBitrate="'Tốc độ bit' tối đa"
|
||||
Preset="Mẫu thiết lập"
|
||||
|
|
@ -8,6 +9,7 @@ RateControl="Cách kiểm soát bitrate"
|
|||
KeyframeIntervalSec="Thời gian đặt Keyframe (giây, 0=tự động)"
|
||||
Lossless="Lossless"
|
||||
|
||||
BFrames="Khung-B tối đa"
|
||||
|
||||
NVENC.Use2Pass="Sử dụng 2-Pass Encoding"
|
||||
NVENC.Preset.default="Hiệu suất"
|
||||
|
|
@ -17,6 +19,7 @@ NVENC.Preset.mq="Chất lượng tối đa"
|
|||
NVENC.Preset.ll="Độ trễ thấp"
|
||||
NVENC.Preset.llhq="Chất lượng \"độ trễ thấp\""
|
||||
NVENC.Preset.llhp="Hiệu suất \"độ trễ thấp\""
|
||||
NVENC.LookAhead="Look-ahead"
|
||||
|
||||
FFmpegSource="Nguồn media"
|
||||
LocalFile="Tập tin cục bộ"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
project(obs-ffmpeg-mux)
|
||||
|
||||
if(DEBUG_FFMPEG_MUX)
|
||||
add_definitions(-DDEBUG_FFMPEG)
|
||||
endif()
|
||||
|
||||
find_package(FFmpeg REQUIRED
|
||||
COMPONENTS avcodec avutil avformat)
|
||||
include_directories(${FFMPEG_INCLUDE_DIRS})
|
||||
|
|
@ -15,6 +19,7 @@ add_executable(obs-ffmpeg-mux
|
|||
${obs-ffmpeg-mux_HEADERS})
|
||||
|
||||
target_link_libraries(obs-ffmpeg-mux
|
||||
libobs
|
||||
${FFMPEG_LIBRARIES})
|
||||
|
||||
set_target_properties(obs-ffmpeg-mux PROPERTIES FOLDER "plugins/obs-ffmpeg")
|
||||
|
|
|
|||
|
|
@ -22,13 +22,17 @@
|
|||
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ffmpeg-mux.h"
|
||||
|
||||
#include <util/dstr.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#define ANSI_COLOR_RED "\x1b[0;91m"
|
||||
#define ANSI_COLOR_MAGENTA "\x1b[0;95m"
|
||||
#define ANSI_COLOR_RESET "\x1b[0m"
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 58
|
||||
#define CODEC_FLAG_GLOBAL_H AV_CODEC_FLAG_GLOBAL_HEADER
|
||||
#else
|
||||
|
|
@ -37,6 +41,8 @@
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static char *global_stream_key = "";
|
||||
|
||||
struct resize_buf {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
|
|
@ -70,6 +76,8 @@ static inline void resize_buf_free(struct resize_buf *rb)
|
|||
|
||||
struct main_params {
|
||||
char *file;
|
||||
/* printable_file is file with any stream key information removed */
|
||||
struct dstr printable_file;
|
||||
int has_video;
|
||||
int tracks;
|
||||
char *vcodec;
|
||||
|
|
@ -172,6 +180,8 @@ static void ffmpeg_mux_free(struct ffmpeg_mux *ffm)
|
|||
free(ffm->audio);
|
||||
}
|
||||
|
||||
dstr_free(&ffm->params.printable_file);
|
||||
|
||||
memset(ffm, 0, sizeof(*ffm));
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +228,44 @@ static bool get_audio_params(struct audio_params *audio, int *argc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ffmpeg_log_callback(void *param, int level, const char *format,
|
||||
va_list args)
|
||||
{
|
||||
#ifdef DEBUG_FFMPEG
|
||||
char out_buffer[4096];
|
||||
struct dstr out = {0};
|
||||
|
||||
vsnprintf(out_buffer, sizeof(out_buffer), format, args);
|
||||
dstr_copy(&out, out_buffer);
|
||||
dstr_replace(&out, global_stream_key, "{stream_key}");
|
||||
|
||||
switch (level) {
|
||||
case AV_LOG_INFO:
|
||||
fprintf(stdout, "info: [ffmpeg_muxer] %s", out.array);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case AV_LOG_WARNING:
|
||||
fprintf(stdout, "%swarning: [ffmpeg_muxer] %s%s",
|
||||
ANSI_COLOR_MAGENTA, out.array, ANSI_COLOR_RESET);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case AV_LOG_ERROR:
|
||||
fprintf(stderr, "%serror: [ffmpeg_muxer] %s%s", ANSI_COLOR_RED,
|
||||
out.array, ANSI_COLOR_RESET);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
dstr_free(&out);
|
||||
#else
|
||||
UNUSED_PARAMETER(level);
|
||||
UNUSED_PARAMETER(format);
|
||||
UNUSED_PARAMETER(args);
|
||||
#endif
|
||||
UNUSED_PARAMETER(param);
|
||||
}
|
||||
|
||||
static bool init_params(int *argc, char ***argv, struct main_params *params,
|
||||
struct audio_params **p_audio)
|
||||
{
|
||||
|
|
@ -287,6 +335,16 @@ static bool init_params(int *argc, char ***argv, struct main_params *params,
|
|||
|
||||
*p_audio = audio;
|
||||
|
||||
dstr_copy(¶ms->printable_file, params->file);
|
||||
|
||||
get_opt_str(argc, argv, &global_stream_key, "stream key");
|
||||
if (strcmp(global_stream_key, "") != 0) {
|
||||
dstr_replace(¶ms->printable_file, global_stream_key,
|
||||
"{stream_key}");
|
||||
}
|
||||
|
||||
av_log_set_callback(ffmpeg_log_callback);
|
||||
|
||||
get_opt_str(argc, argv, ¶ms->muxer_settings, "muxer settings");
|
||||
|
||||
return true;
|
||||
|
|
@ -353,6 +411,10 @@ static void create_video_stream(struct ffmpeg_mux *ffm)
|
|||
(AVRational){ffm->params.fps_den, ffm->params.fps_num};
|
||||
|
||||
ffm->video_stream->time_base = context->time_base;
|
||||
#if LIBAVFORMAT_VERSION_MAJOR < 59
|
||||
// codec->time_base may still be used if LIBAVFORMAT_VERSION_MAJOR < 59
|
||||
ffm->video_stream->codec->time_base = context->time_base;
|
||||
#endif
|
||||
ffm->video_stream->avg_frame_rate = av_inv_q(context->time_base);
|
||||
|
||||
if (ffm->output->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
|
|
@ -521,7 +583,8 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
|||
AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't open '%s', %s\n",
|
||||
ffm->params.file, av_err2str(ret));
|
||||
ffm->params.printable_file.array,
|
||||
av_err2str(ret));
|
||||
return FFM_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
@ -548,8 +611,8 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
|||
|
||||
ret = avformat_write_header(ffm->output, &dict);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error opening '%s': %s\n", ffm->params.file,
|
||||
av_err2str(ret));
|
||||
fprintf(stderr, "Error opening '%s': %s",
|
||||
ffm->params.printable_file.array, av_err2str(ret));
|
||||
|
||||
av_dict_free(&dict);
|
||||
|
||||
|
|
@ -564,29 +627,43 @@ static inline int open_output_file(struct ffmpeg_mux *ffm)
|
|||
#define SRT_PROTO "srt"
|
||||
#define UDP_PROTO "udp"
|
||||
#define TCP_PROTO "tcp"
|
||||
#define HTTP_PROTO "http"
|
||||
|
||||
static bool ffmpeg_mux_is_network(struct ffmpeg_mux *ffm)
|
||||
{
|
||||
return !strncmp(ffm->params.file, SRT_PROTO, sizeof(SRT_PROTO) - 1) ||
|
||||
!strncmp(ffm->params.file, UDP_PROTO, sizeof(UDP_PROTO) - 1) ||
|
||||
!strncmp(ffm->params.file, TCP_PROTO, sizeof(TCP_PROTO) - 1) ||
|
||||
!strncmp(ffm->params.file, HTTP_PROTO, sizeof(HTTP_PROTO) - 1);
|
||||
}
|
||||
|
||||
static int ffmpeg_mux_init_context(struct ffmpeg_mux *ffm)
|
||||
{
|
||||
AVOutputFormat *output_format;
|
||||
int ret;
|
||||
bool isNetwork = false;
|
||||
if (strncmp(ffm->params.file, SRT_PROTO, sizeof(SRT_PROTO) - 1) == 0 ||
|
||||
strncmp(ffm->params.file, UDP_PROTO, sizeof(UDP_PROTO) - 1) == 0 ||
|
||||
strncmp(ffm->params.file, TCP_PROTO, sizeof(TCP_PROTO) - 1) == 0)
|
||||
isNetwork = true;
|
||||
bool is_http = false;
|
||||
is_http = (strncmp(ffm->params.file, HTTP_PROTO,
|
||||
sizeof(HTTP_PROTO) - 1) == 0);
|
||||
|
||||
if (isNetwork) {
|
||||
bool is_network = ffmpeg_mux_is_network(ffm);
|
||||
|
||||
if (is_network) {
|
||||
avformat_network_init();
|
||||
output_format = av_guess_format("mpegts", NULL, "video/M2PT");
|
||||
} else {
|
||||
output_format = av_guess_format(NULL, ffm->params.file, NULL);
|
||||
}
|
||||
|
||||
if (is_network && !is_http)
|
||||
output_format = av_guess_format("mpegts", NULL, "video/M2PT");
|
||||
else
|
||||
output_format = av_guess_format(NULL, ffm->params.file, NULL);
|
||||
|
||||
if (output_format == NULL) {
|
||||
fprintf(stderr, "Couldn't find an appropriate muxer for '%s'\n",
|
||||
ffm->params.file);
|
||||
ffm->params.printable_file.array);
|
||||
return FFM_ERROR;
|
||||
}
|
||||
printf("info: Output format name and long_name: %s, %s\n",
|
||||
output_format->name ? output_format->name : "unknown",
|
||||
output_format->long_name ? output_format->long_name : "unknown");
|
||||
|
||||
ret = avformat_alloc_output_context2(&ffm->output, output_format, NULL,
|
||||
ffm->params.file);
|
||||
|
|
@ -726,8 +803,13 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf,
|
|||
int ret = av_interleaved_write_frame(ffm->output, &packet);
|
||||
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "av_interleaved_write_frame failed: %s\n",
|
||||
av_err2str(ret));
|
||||
fprintf(stderr, "av_interleaved_write_frame failed: %d: %s\n",
|
||||
ret, av_err2str(ret));
|
||||
}
|
||||
|
||||
/* Treat "Invalid data found when processing input" and "Invalid argument" as non-fatal */
|
||||
if (ret == AVERROR_INVALIDDATA || ret == EINVAL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ret >= 0;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum ffm_packet_type {
|
||||
|
|
|
|||
|
|
@ -426,6 +426,14 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
|
|||
config->gopLength = gop_size;
|
||||
config->frameIntervalP = 1 + bf;
|
||||
h264_config->idrPeriod = gop_size;
|
||||
|
||||
bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
|
||||
if (repeat_headers) {
|
||||
h264_config->repeatSPSPPS = 1;
|
||||
h264_config->disableSPSPPS = 0;
|
||||
h264_config->outputAUD = 1;
|
||||
}
|
||||
|
||||
vui_params->videoSignalTypePresentFlag = 1;
|
||||
vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
|
||||
vui_params->colourDescriptionPresentFlag = 1;
|
||||
|
|
|
|||
332
plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c
Normal file
332
plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
#include "obs-ffmpeg-mux.h"
|
||||
|
||||
#define do_log(level, format, ...) \
|
||||
blog(level, "[ffmpeg hls muxer: '%s'] " format, \
|
||||
obs_output_get_name(stream->output), ##__VA_ARGS__)
|
||||
|
||||
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
|
||||
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
|
||||
|
||||
const char *ffmpeg_hls_mux_getname(void *type)
|
||||
{
|
||||
UNUSED_PARAMETER(type);
|
||||
return obs_module_text("FFmpegHlsMuxer");
|
||||
}
|
||||
|
||||
int hls_stream_dropped_frames(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
return stream->dropped_frames;
|
||||
}
|
||||
|
||||
void ffmpeg_hls_mux_destroy(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
if (stream) {
|
||||
deactivate(stream, 0);
|
||||
|
||||
pthread_mutex_destroy(&stream->write_mutex);
|
||||
os_sem_destroy(stream->write_sem);
|
||||
os_event_destroy(stream->stop_event);
|
||||
|
||||
da_free(stream->mux_packets);
|
||||
circlebuf_free(&stream->packets);
|
||||
|
||||
os_process_pipe_destroy(stream->pipe);
|
||||
dstr_free(&stream->path);
|
||||
dstr_free(&stream->printable_path);
|
||||
dstr_free(&stream->stream_key);
|
||||
dstr_free(&stream->muxer_settings);
|
||||
bfree(data);
|
||||
}
|
||||
}
|
||||
|
||||
void *ffmpeg_hls_mux_create(obs_data_t *settings, obs_output_t *output)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = bzalloc(sizeof(*stream));
|
||||
pthread_mutex_init_value(&stream->write_mutex);
|
||||
stream->output = output;
|
||||
|
||||
/* init mutex, semaphore and event */
|
||||
if (pthread_mutex_init(&stream->write_mutex, NULL) != 0)
|
||||
goto fail;
|
||||
if (os_event_init(&stream->stop_event, OS_EVENT_TYPE_AUTO) != 0)
|
||||
goto fail;
|
||||
if (os_sem_init(&stream->write_sem, 0) != 0)
|
||||
goto fail;
|
||||
|
||||
UNUSED_PARAMETER(settings);
|
||||
return stream;
|
||||
|
||||
fail:
|
||||
ffmpeg_hls_mux_destroy(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool process_packet(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
struct encoder_packet packet;
|
||||
bool has_packet = false;
|
||||
bool ret = true;
|
||||
|
||||
pthread_mutex_lock(&stream->write_mutex);
|
||||
|
||||
if (stream->packets.size) {
|
||||
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
|
||||
has_packet = true;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stream->write_mutex);
|
||||
|
||||
if (has_packet) {
|
||||
ret = write_packet(stream, &packet);
|
||||
obs_encoder_packet_release(&packet);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *write_thread(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
while (os_sem_wait(stream->write_sem) == 0) {
|
||||
if (os_event_try(stream->stop_event) == 0)
|
||||
return NULL;
|
||||
|
||||
if (!process_packet(stream))
|
||||
break;
|
||||
}
|
||||
|
||||
obs_output_signal_stop(stream->output, OBS_OUTPUT_ERROR);
|
||||
deactivate(stream, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffmpeg_hls_mux_start(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
obs_service_t *service;
|
||||
const char *path_str;
|
||||
const char *stream_key;
|
||||
struct dstr path = {0};
|
||||
obs_encoder_t *vencoder;
|
||||
obs_data_t *settings;
|
||||
int keyint_sec;
|
||||
|
||||
if (!obs_output_can_begin_data_capture(stream->output, 0))
|
||||
return false;
|
||||
if (!obs_output_initialize_encoders(stream->output, 0))
|
||||
return false;
|
||||
|
||||
service = obs_output_get_service(stream->output);
|
||||
if (!service)
|
||||
return false;
|
||||
path_str = obs_service_get_url(service);
|
||||
stream_key = obs_service_get_key(service);
|
||||
dstr_copy(&stream->stream_key, stream_key);
|
||||
dstr_copy(&path, path_str);
|
||||
dstr_replace(&path, "{stream_key}", stream_key);
|
||||
dstr_copy(&stream->muxer_settings,
|
||||
"method=PUT http_persistent=1 ignore_io_errors=1 ");
|
||||
dstr_catf(&stream->muxer_settings, "http_user_agent=libobs/%s",
|
||||
OBS_VERSION);
|
||||
|
||||
vencoder = obs_output_get_video_encoder(stream->output);
|
||||
settings = obs_encoder_get_settings(vencoder);
|
||||
keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
|
||||
if (keyint_sec) {
|
||||
dstr_catf(&stream->muxer_settings, " hls_time=%d", keyint_sec);
|
||||
stream->keyint_sec = keyint_sec;
|
||||
}
|
||||
|
||||
obs_data_release(settings);
|
||||
|
||||
start_pipe(stream, path.array);
|
||||
dstr_free(&path);
|
||||
|
||||
if (!stream->pipe) {
|
||||
obs_output_set_last_error(
|
||||
stream->output, obs_module_text("HelperProcessFailed"));
|
||||
warn("Failed to create process pipe");
|
||||
return false;
|
||||
}
|
||||
stream->mux_thread_joinable = pthread_create(&stream->mux_thread, NULL,
|
||||
write_thread, stream) == 0;
|
||||
if (!stream->mux_thread_joinable)
|
||||
return false;
|
||||
|
||||
/* write headers and start capture */
|
||||
os_atomic_set_bool(&stream->active, true);
|
||||
os_atomic_set_bool(&stream->capturing, true);
|
||||
stream->is_hls = true;
|
||||
stream->total_bytes = 0;
|
||||
stream->dropped_frames = 0;
|
||||
stream->min_priority = 0;
|
||||
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
|
||||
dstr_copy(&stream->printable_path, path_str);
|
||||
info("Writing to path '%s'...", stream->printable_path.array);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet_to_buf(struct ffmpeg_muxer *stream,
|
||||
struct encoder_packet *packet)
|
||||
{
|
||||
circlebuf_push_back(&stream->packets, packet,
|
||||
sizeof(struct encoder_packet));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void drop_frames(struct ffmpeg_muxer *stream, int highest_priority)
|
||||
{
|
||||
struct circlebuf new_buf = {0};
|
||||
int num_frames_dropped = 0;
|
||||
|
||||
circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8);
|
||||
|
||||
while (stream->packets.size) {
|
||||
struct encoder_packet packet;
|
||||
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
|
||||
|
||||
/* do not drop audio data or video keyframes */
|
||||
if (packet.type == OBS_ENCODER_AUDIO ||
|
||||
packet.drop_priority >= highest_priority) {
|
||||
circlebuf_push_back(&new_buf, &packet, sizeof(packet));
|
||||
} else {
|
||||
num_frames_dropped++;
|
||||
obs_encoder_packet_release(&packet);
|
||||
}
|
||||
}
|
||||
|
||||
circlebuf_free(&stream->packets);
|
||||
stream->packets = new_buf;
|
||||
|
||||
if (stream->min_priority < highest_priority)
|
||||
stream->min_priority = highest_priority;
|
||||
|
||||
stream->dropped_frames += num_frames_dropped;
|
||||
}
|
||||
|
||||
static bool find_first_video_packet(struct ffmpeg_muxer *stream,
|
||||
struct encoder_packet *first)
|
||||
{
|
||||
size_t count = stream->packets.size / sizeof(*first);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
struct encoder_packet *cur =
|
||||
circlebuf_data(&stream->packets, i * sizeof(*first));
|
||||
if (cur->type == OBS_ENCODER_VIDEO && !cur->keyframe) {
|
||||
*first = *cur;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_to_drop_frames(struct ffmpeg_muxer *stream, bool pframes)
|
||||
{
|
||||
struct encoder_packet first;
|
||||
int64_t buffer_duration_usec;
|
||||
int priority = pframes ? OBS_NAL_PRIORITY_HIGHEST
|
||||
: OBS_NAL_PRIORITY_HIGH;
|
||||
int keyint_sec = stream->keyint_sec;
|
||||
int64_t drop_threshold_sec = keyint_sec ? 2 * keyint_sec : 10;
|
||||
|
||||
if (!find_first_video_packet(stream, &first))
|
||||
return;
|
||||
|
||||
buffer_duration_usec = stream->last_dts_usec - first.dts_usec;
|
||||
|
||||
if (buffer_duration_usec > drop_threshold_sec * 1000000)
|
||||
drop_frames(stream, priority);
|
||||
}
|
||||
|
||||
static bool add_video_packet(struct ffmpeg_muxer *stream,
|
||||
struct encoder_packet *packet)
|
||||
{
|
||||
check_to_drop_frames(stream, false);
|
||||
check_to_drop_frames(stream, true);
|
||||
|
||||
/* if currently dropping frames, drop packets until it reaches the
|
||||
* desired priority */
|
||||
if (packet->drop_priority < stream->min_priority) {
|
||||
stream->dropped_frames++;
|
||||
return false;
|
||||
} else {
|
||||
stream->min_priority = 0;
|
||||
}
|
||||
|
||||
stream->last_dts_usec = packet->dts_usec;
|
||||
return write_packet_to_buf(stream, packet);
|
||||
}
|
||||
|
||||
void ffmpeg_hls_mux_data(void *data, struct encoder_packet *packet)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
struct encoder_packet new_packet;
|
||||
struct encoder_packet tmp_packet;
|
||||
bool added_packet = false;
|
||||
|
||||
if (!active(stream))
|
||||
return;
|
||||
|
||||
/* encoder failure */
|
||||
if (!packet) {
|
||||
deactivate(stream, OBS_OUTPUT_ENCODE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stream->sent_headers) {
|
||||
if (!send_headers(stream))
|
||||
return;
|
||||
stream->sent_headers = true;
|
||||
}
|
||||
|
||||
if (stopping(stream)) {
|
||||
if (packet->sys_dts_usec >= stream->stop_ts) {
|
||||
deactivate(stream, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->type == OBS_ENCODER_VIDEO) {
|
||||
obs_parse_avc_packet(&tmp_packet, packet);
|
||||
packet->drop_priority = tmp_packet.priority;
|
||||
obs_encoder_packet_release(&tmp_packet);
|
||||
}
|
||||
obs_encoder_packet_ref(&new_packet, packet);
|
||||
|
||||
pthread_mutex_lock(&stream->write_mutex);
|
||||
|
||||
if (active(stream)) {
|
||||
added_packet =
|
||||
(packet->type == OBS_ENCODER_VIDEO)
|
||||
? add_video_packet(stream, &new_packet)
|
||||
: write_packet_to_buf(stream, &new_packet);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stream->write_mutex);
|
||||
|
||||
if (added_packet)
|
||||
os_sem_post(stream->write_sem);
|
||||
else
|
||||
obs_encoder_packet_release(&new_packet);
|
||||
}
|
||||
|
||||
struct obs_output_info ffmpeg_hls_muxer = {
|
||||
.id = "ffmpeg_hls_muxer",
|
||||
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK |
|
||||
OBS_OUTPUT_SERVICE,
|
||||
.encoded_video_codecs = "h264",
|
||||
.encoded_audio_codecs = "aac",
|
||||
.get_name = ffmpeg_hls_mux_getname,
|
||||
.create = ffmpeg_hls_mux_create,
|
||||
.destroy = ffmpeg_hls_mux_destroy,
|
||||
.start = ffmpeg_hls_mux_start,
|
||||
.stop = ffmpeg_mux_stop,
|
||||
.encoded_packet = ffmpeg_hls_mux_data,
|
||||
.get_total_bytes = ffmpeg_mux_total_bytes,
|
||||
.get_dropped_frames = hls_stream_dropped_frames,
|
||||
};
|
||||
|
|
@ -14,17 +14,8 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <obs-module.h>
|
||||
#include <obs-hotkey.h>
|
||||
#include <obs-avc.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/pipe.h>
|
||||
#include <util/darray.h>
|
||||
#include <util/platform.h>
|
||||
#include <util/circlebuf.h>
|
||||
#include <util/threading.h>
|
||||
#include "ffmpeg-mux/ffmpeg-mux.h"
|
||||
#include "obs-ffmpeg-mux.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "util/windows/win-version.h"
|
||||
|
|
@ -39,35 +30,6 @@
|
|||
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
|
||||
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
|
||||
|
||||
struct ffmpeg_muxer {
|
||||
obs_output_t *output;
|
||||
os_process_pipe_t *pipe;
|
||||
int64_t stop_ts;
|
||||
uint64_t total_bytes;
|
||||
struct dstr path;
|
||||
bool sent_headers;
|
||||
volatile bool active;
|
||||
volatile bool stopping;
|
||||
volatile bool capturing;
|
||||
|
||||
/* replay buffer */
|
||||
struct circlebuf packets;
|
||||
int64_t cur_size;
|
||||
int64_t cur_time;
|
||||
int64_t max_size;
|
||||
int64_t max_time;
|
||||
int64_t save_ts;
|
||||
int keyframes;
|
||||
obs_hotkey_id hotkey;
|
||||
|
||||
DARRAY(struct encoder_packet) mux_packets;
|
||||
pthread_t mux_thread;
|
||||
bool mux_thread_joinable;
|
||||
volatile bool muxing;
|
||||
|
||||
bool is_network;
|
||||
};
|
||||
|
||||
static const char *ffmpeg_mux_getname(void *type)
|
||||
{
|
||||
UNUSED_PARAMETER(type);
|
||||
|
|
@ -105,9 +67,13 @@ static void ffmpeg_mux_destroy(void *data)
|
|||
if (stream->mux_thread_joinable)
|
||||
pthread_join(stream->mux_thread, NULL);
|
||||
da_free(stream->mux_packets);
|
||||
circlebuf_free(&stream->packets);
|
||||
|
||||
os_process_pipe_destroy(stream->pipe);
|
||||
dstr_free(&stream->path);
|
||||
dstr_free(&stream->printable_path);
|
||||
dstr_free(&stream->stream_key);
|
||||
dstr_free(&stream->muxer_settings);
|
||||
bfree(stream);
|
||||
}
|
||||
|
||||
|
|
@ -134,12 +100,12 @@ static inline bool capturing(struct ffmpeg_muxer *stream)
|
|||
return os_atomic_load_bool(&stream->capturing);
|
||||
}
|
||||
|
||||
static inline bool stopping(struct ffmpeg_muxer *stream)
|
||||
bool stopping(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->stopping);
|
||||
}
|
||||
|
||||
static inline bool active(struct ffmpeg_muxer *stream)
|
||||
bool active(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->active);
|
||||
}
|
||||
|
|
@ -236,17 +202,30 @@ static void log_muxer_params(struct ffmpeg_muxer *stream, const char *settings)
|
|||
av_dict_free(&dict);
|
||||
}
|
||||
|
||||
static void add_stream_key(struct dstr *cmd, struct ffmpeg_muxer *stream)
|
||||
{
|
||||
dstr_catf(cmd, "\"%s\" ",
|
||||
dstr_is_empty(&stream->stream_key)
|
||||
? ""
|
||||
: stream->stream_key.array);
|
||||
}
|
||||
|
||||
static void add_muxer_params(struct dstr *cmd, struct ffmpeg_muxer *stream)
|
||||
{
|
||||
obs_data_t *settings = obs_output_get_settings(stream->output);
|
||||
struct dstr mux = {0};
|
||||
|
||||
dstr_copy(&mux, obs_data_get_string(settings, "muxer_settings"));
|
||||
if (dstr_is_empty(&stream->muxer_settings)) {
|
||||
obs_data_t *settings = obs_output_get_settings(stream->output);
|
||||
dstr_copy(&mux,
|
||||
obs_data_get_string(settings, "muxer_settings"));
|
||||
obs_data_release(settings);
|
||||
} else {
|
||||
dstr_copy(&mux, stream->muxer_settings.array);
|
||||
}
|
||||
|
||||
log_muxer_params(stream, mux.array);
|
||||
|
||||
dstr_replace(&mux, "\"", "\\\"");
|
||||
obs_data_release(settings);
|
||||
|
||||
dstr_catf(cmd, "\"%s\" ", mux.array ? mux.array : "");
|
||||
|
||||
|
|
@ -291,10 +270,11 @@ static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd,
|
|||
}
|
||||
}
|
||||
|
||||
add_stream_key(cmd, stream);
|
||||
add_muxer_params(cmd, stream);
|
||||
}
|
||||
|
||||
static inline void start_pipe(struct ffmpeg_muxer *stream, const char *path)
|
||||
void start_pipe(struct ffmpeg_muxer *stream, const char *path)
|
||||
{
|
||||
struct dstr cmd;
|
||||
build_command_line(stream, &cmd, path);
|
||||
|
|
@ -381,10 +361,19 @@ static bool ffmpeg_mux_start(void *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int deactivate(struct ffmpeg_muxer *stream, int code)
|
||||
int deactivate(struct ffmpeg_muxer *stream, int code)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stream->is_hls) {
|
||||
if (stream->mux_thread_joinable) {
|
||||
os_event_signal(stream->stop_event);
|
||||
os_sem_post(stream->write_sem);
|
||||
pthread_join(stream->mux_thread, NULL);
|
||||
stream->mux_thread_joinable = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (active(stream)) {
|
||||
ret = os_process_pipe_destroy(stream->pipe);
|
||||
stream->pipe = NULL;
|
||||
|
|
@ -392,7 +381,10 @@ static int deactivate(struct ffmpeg_muxer *stream, int code)
|
|||
os_atomic_set_bool(&stream->active, false);
|
||||
os_atomic_set_bool(&stream->sent_headers, false);
|
||||
|
||||
info("Output of file '%s' stopped", stream->path.array);
|
||||
info("Output of file '%s' stopped",
|
||||
dstr_is_empty(&stream->printable_path)
|
||||
? stream->path.array
|
||||
: stream->printable_path.array);
|
||||
}
|
||||
|
||||
if (code) {
|
||||
|
|
@ -401,11 +393,24 @@ static int deactivate(struct ffmpeg_muxer *stream, int code)
|
|||
obs_output_end_data_capture(stream->output);
|
||||
}
|
||||
|
||||
if (stream->is_hls) {
|
||||
pthread_mutex_lock(&stream->write_mutex);
|
||||
|
||||
while (stream->packets.size) {
|
||||
struct encoder_packet packet;
|
||||
circlebuf_pop_front(&stream->packets, &packet,
|
||||
sizeof(packet));
|
||||
obs_encoder_packet_release(&packet);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stream->write_mutex);
|
||||
}
|
||||
|
||||
os_atomic_set_bool(&stream->stopping, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ffmpeg_mux_stop(void *data, uint64_t ts)
|
||||
void ffmpeg_mux_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
|
|
@ -451,8 +456,7 @@ static void signal_failure(struct ffmpeg_muxer *stream)
|
|||
os_atomic_set_bool(&stream->capturing, false);
|
||||
}
|
||||
|
||||
static bool write_packet(struct ffmpeg_muxer *stream,
|
||||
struct encoder_packet *packet)
|
||||
bool write_packet(struct ffmpeg_muxer *stream, struct encoder_packet *packet)
|
||||
{
|
||||
bool is_video = packet->type == OBS_ENCODER_VIDEO;
|
||||
size_t ret;
|
||||
|
|
@ -505,7 +509,7 @@ static bool send_video_headers(struct ffmpeg_muxer *stream)
|
|||
return write_packet(stream, &packet);
|
||||
}
|
||||
|
||||
static bool send_headers(struct ffmpeg_muxer *stream)
|
||||
bool send_headers(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
obs_encoder_t *aencoder;
|
||||
size_t idx = 0;
|
||||
|
|
@ -567,7 +571,7 @@ static obs_properties_t *ffmpeg_mux_properties(void *unused)
|
|||
return props;
|
||||
}
|
||||
|
||||
static uint64_t ffmpeg_mux_total_bytes(void *data)
|
||||
uint64_t ffmpeg_mux_total_bytes(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
return stream->total_bytes;
|
||||
|
|
@ -646,6 +650,12 @@ static void replay_buffer_hotkey(void *data, obs_hotkey_id id,
|
|||
return;
|
||||
}
|
||||
|
||||
calldata_t cd = {0};
|
||||
|
||||
signal_handler_t *sh =
|
||||
obs_output_get_signal_handler(stream->output);
|
||||
signal_handler_signal(sh, "saved", &cd);
|
||||
|
||||
stream->save_ts = os_gettime_ns() / 1000LL;
|
||||
}
|
||||
}
|
||||
|
|
@ -679,6 +689,9 @@ static void *replay_buffer_create(obs_data_t *settings, obs_output_t *output)
|
|||
proc_handler_add(ph, "void get_last_replay(out string path)",
|
||||
get_last_replay, stream);
|
||||
|
||||
signal_handler_t *sh = obs_output_get_signal_handler(output);
|
||||
signal_handler_add(sh, "void saved()");
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
|
|
|||
63
plugins/obs-ffmpeg/obs-ffmpeg-mux.h
Normal file
63
plugins/obs-ffmpeg/obs-ffmpeg-mux.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <obs-avc.h>
|
||||
#include <obs-module.h>
|
||||
#include <obs-hotkey.h>
|
||||
#include <util/circlebuf.h>
|
||||
#include <util/darray.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/pipe.h>
|
||||
#include <util/platform.h>
|
||||
#include <util/threading.h>
|
||||
|
||||
struct ffmpeg_muxer {
|
||||
obs_output_t *output;
|
||||
os_process_pipe_t *pipe;
|
||||
int64_t stop_ts;
|
||||
uint64_t total_bytes;
|
||||
bool sent_headers;
|
||||
volatile bool active;
|
||||
volatile bool capturing;
|
||||
volatile bool stopping;
|
||||
struct dstr path;
|
||||
struct dstr printable_path;
|
||||
struct dstr muxer_settings;
|
||||
struct dstr stream_key;
|
||||
|
||||
/* replay buffer */
|
||||
int64_t cur_size;
|
||||
int64_t cur_time;
|
||||
int64_t max_size;
|
||||
int64_t max_time;
|
||||
int64_t save_ts;
|
||||
int keyframes;
|
||||
obs_hotkey_id hotkey;
|
||||
volatile bool muxing;
|
||||
DARRAY(struct encoder_packet) mux_packets;
|
||||
|
||||
/* these are accessed both by replay buffer and by HLS */
|
||||
pthread_t mux_thread;
|
||||
bool mux_thread_joinable;
|
||||
struct circlebuf packets;
|
||||
|
||||
/* HLS only */
|
||||
int keyint_sec;
|
||||
pthread_mutex_t write_mutex;
|
||||
os_sem_t *write_sem;
|
||||
os_event_t *stop_event;
|
||||
bool is_hls;
|
||||
int dropped_frames;
|
||||
int min_priority;
|
||||
int64_t last_dts_usec;
|
||||
|
||||
bool is_network;
|
||||
};
|
||||
|
||||
bool stopping(struct ffmpeg_muxer *stream);
|
||||
bool active(struct ffmpeg_muxer *stream);
|
||||
void start_pipe(struct ffmpeg_muxer *stream, const char *path);
|
||||
bool write_packet(struct ffmpeg_muxer *stream, struct encoder_packet *packet);
|
||||
bool send_headers(struct ffmpeg_muxer *stream);
|
||||
int deactivate(struct ffmpeg_muxer *stream, int code);
|
||||
void ffmpeg_mux_stop(void *data, uint64_t ts);
|
||||
uint64_t ffmpeg_mux_total_bytes(void *data);
|
||||
|
|
@ -477,6 +477,7 @@ void nvenc_defaults(obs_data_t *settings)
|
|||
obs_data_set_default_bool(settings, "psycho_aq", true);
|
||||
obs_data_set_default_int(settings, "gpu", 0);
|
||||
obs_data_set_default_int(settings, "bf", 2);
|
||||
obs_data_set_default_bool(settings, "repeat_headers", false);
|
||||
}
|
||||
|
||||
static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
|
||||
|
|
@ -576,6 +577,9 @@ obs_properties_t *nvenc_properties_internal(bool ffmpeg)
|
|||
obs_module_text("NVENC.PsychoVisualTuning"));
|
||||
obs_property_set_long_description(
|
||||
p, obs_module_text("NVENC.PsychoVisualTuning.ToolTip"));
|
||||
p = obs_properties_add_bool(props, "repeat_headers",
|
||||
"repeat_headers");
|
||||
obs_property_set_visible(p, false);
|
||||
}
|
||||
|
||||
obs_properties_add_int(props, "gpu", obs_module_text("GPU"), 0, 8, 1);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ extern struct obs_output_info ffmpeg_output;
|
|||
extern struct obs_output_info ffmpeg_muxer;
|
||||
extern struct obs_output_info ffmpeg_mpegts_muxer;
|
||||
extern struct obs_output_info replay_buffer;
|
||||
extern struct obs_output_info ffmpeg_hls_muxer;
|
||||
extern struct obs_encoder_info aac_encoder_info;
|
||||
extern struct obs_encoder_info opus_encoder_info;
|
||||
extern struct obs_encoder_info nvenc_encoder_info;
|
||||
|
|
@ -81,6 +82,7 @@ static const int blacklisted_adapters[] = {
|
|||
0x1d11, // GP108M [GeForce MX230]
|
||||
0x1d13, // GP108M [GeForce MX250]
|
||||
0x1d52, // GP108BM [GeForce MX250]
|
||||
0x1c94, // GP107 [GeForce MX350]
|
||||
0x137b, // GM108GLM [Quadro M520 Mobile]
|
||||
0x1d33, // GP108GLM [Quadro P500 Mobile]
|
||||
0x137a, // GM108GLM [Quadro K620M / Quadro M500M]
|
||||
|
|
@ -231,6 +233,7 @@ bool obs_module_load(void)
|
|||
obs_register_output(&ffmpeg_output);
|
||||
obs_register_output(&ffmpeg_muxer);
|
||||
obs_register_output(&ffmpeg_mpegts_muxer);
|
||||
obs_register_output(&ffmpeg_hls_muxer);
|
||||
obs_register_output(&replay_buffer);
|
||||
obs_register_encoder(&aac_encoder_info);
|
||||
obs_register_encoder(&opus_encoder_info);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue