New upstream version 19.0.3+dfsg1
This commit is contained in:
parent
3708b8e092
commit
1f1bbb3518
534 changed files with 13862 additions and 2459 deletions
110
plugins/decklink/audio-repack.c
Normal file
110
plugins/decklink/audio-repack.c
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#include "audio-repack.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
int check_buffer(struct audio_repack *repack,
|
||||
uint32_t frame_count)
|
||||
{
|
||||
const uint32_t new_size = frame_count * repack->base_dst_size
|
||||
+ repack->extra_dst_size;
|
||||
|
||||
if (repack->packet_size < new_size) {
|
||||
repack->packet_buffer = brealloc(
|
||||
repack->packet_buffer, new_size);
|
||||
if (!repack->packet_buffer)
|
||||
return -1;
|
||||
|
||||
repack->packet_size = new_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Swap channel between LFE and FC, and
|
||||
squash data array
|
||||
|
||||
| FL | FR |LFE | FC | BL | BR |emp |emp |
|
||||
| | x | |
|
||||
| FL | FR | FC |LFE | BL | BR |
|
||||
*/
|
||||
int repack_8to6ch_swap23(struct audio_repack *repack,
|
||||
const uint8_t *bsrc, uint32_t frame_count)
|
||||
{
|
||||
if (check_buffer(repack, frame_count) < 0)
|
||||
return -1;
|
||||
|
||||
const __m128i *src = (__m128i *)bsrc;
|
||||
const __m128i *esrc = src + frame_count;
|
||||
uint32_t *dst = (uint32_t *)repack->packet_buffer;
|
||||
while (src != esrc) {
|
||||
__m128i target = _mm_load_si128(src++);
|
||||
__m128i buf = _mm_shufflelo_epi16(target, _MM_SHUFFLE(2, 3, 1, 0));
|
||||
_mm_storeu_si128((__m128i *)dst, buf);
|
||||
dst += 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Swap channel between LFE and FC
|
||||
|
||||
| FL | FR |LFE | FC | BL | BR |SBL |SBR |
|
||||
| | x | | | |
|
||||
| FL | FR | FC |LFE | BL | BR |SBL |SBR |
|
||||
*/
|
||||
int repack_8ch_swap23(struct audio_repack *repack,
|
||||
const uint8_t *bsrc, uint32_t frame_count)
|
||||
{
|
||||
if (check_buffer(repack, frame_count) < 0)
|
||||
return -1;
|
||||
|
||||
const __m128i *src = (__m128i *)bsrc;
|
||||
const __m128i *esrc = src + frame_count;
|
||||
__m128i *dst = (__m128i *)repack->packet_buffer;
|
||||
while (src != esrc) {
|
||||
__m128i target = _mm_load_si128(src++);
|
||||
__m128i buf = _mm_shufflelo_epi16(target, _MM_SHUFFLE(2, 3, 1, 0));
|
||||
_mm_store_si128(dst++, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_repack_init(struct audio_repack *repack,
|
||||
audio_repack_mode_t repack_mode, uint8_t sample_bit)
|
||||
{
|
||||
memset(repack, 0, sizeof(*repack));
|
||||
|
||||
if (sample_bit != 16)
|
||||
return -1;
|
||||
|
||||
switch (repack_mode) {
|
||||
case repack_mode_8to6ch_swap23:
|
||||
repack->base_src_size = 8 * (16 / 8);
|
||||
repack->base_dst_size = 6 * (16 / 8);
|
||||
repack->extra_dst_size = 2;
|
||||
repack->repack_func = &repack_8to6ch_swap23;
|
||||
break;
|
||||
|
||||
case repack_mode_8ch_swap23:
|
||||
repack->base_src_size = 8 * (16 / 8);
|
||||
repack->base_dst_size = 8 * (16 / 8);
|
||||
repack->extra_dst_size = 0;
|
||||
repack->repack_func = &repack_8ch_swap23;
|
||||
break;
|
||||
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_repack_free(struct audio_repack *repack)
|
||||
{
|
||||
if (repack->packet_buffer)
|
||||
bfree(repack->packet_buffer);
|
||||
|
||||
memset(repack, 0, sizeof(*repack));
|
||||
}
|
||||
41
plugins/decklink/audio-repack.h
Normal file
41
plugins/decklink/audio-repack.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <obs.h>
|
||||
|
||||
struct audio_repack;
|
||||
|
||||
typedef int (*audio_repack_func_t)(struct audio_repack *,
|
||||
const uint8_t *, uint32_t);
|
||||
|
||||
struct audio_repack {
|
||||
uint8_t *packet_buffer;
|
||||
uint32_t packet_size;
|
||||
|
||||
uint32_t base_src_size;
|
||||
uint32_t base_dst_size;
|
||||
uint32_t extra_dst_size;
|
||||
|
||||
audio_repack_func_t repack_func;
|
||||
};
|
||||
|
||||
enum _audio_repack_mode {
|
||||
repack_mode_8to6ch_swap23,
|
||||
repack_mode_8ch_swap23,
|
||||
};
|
||||
|
||||
typedef enum _audio_repack_mode audio_repack_mode_t;
|
||||
|
||||
extern int audio_repack_init(struct audio_repack *repack,
|
||||
audio_repack_mode_t repack_mode, uint8_t sample_bit);
|
||||
extern void audio_repack_free(struct audio_repack *repack);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
25
plugins/decklink/audio-repack.hpp
Normal file
25
plugins/decklink/audio-repack.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "audio-repack.h"
|
||||
|
||||
class AudioRepacker {
|
||||
struct audio_repack arepack;
|
||||
|
||||
public:
|
||||
inline AudioRepacker(audio_repack_mode_t repack_mode)
|
||||
{
|
||||
audio_repack_init(&arepack, repack_mode, 16);
|
||||
}
|
||||
inline ~AudioRepacker()
|
||||
{
|
||||
audio_repack_free(&arepack);
|
||||
}
|
||||
|
||||
inline int repack(const uint8_t *src, uint32_t frame_size)
|
||||
{
|
||||
return (*arepack.repack_func)(&arepack, src, frame_size);
|
||||
}
|
||||
|
||||
inline operator struct audio_repack*() {return &arepack;}
|
||||
inline struct audio_repack *operator->() {return &arepack;}
|
||||
};
|
||||
4
plugins/decklink/data/locale/bn-BD.ini
Normal file
4
plugins/decklink/data/locale/bn-BD.ini
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
BlackmagicDevice="Blackmagic যন্ত্র"
|
||||
Device="ডিভাইস"
|
||||
PixelFormat="পিক্সেল বিন্যাস"
|
||||
|
||||
|
|
@ -3,4 +3,10 @@ Device="Dispositiu"
|
|||
Mode="Mode"
|
||||
Buffering="Usa memòria intermèdia"
|
||||
PixelFormat="Format de píxel"
|
||||
ChannelFormat="Canal"
|
||||
ChannelFormat.None="Cap"
|
||||
ChannelFormat.2_0ch="Estèreo "
|
||||
ChannelFormat.5_1ch="5.1"
|
||||
ChannelFormat.5_1chBack="5.1 (posterior)"
|
||||
ChannelFormat.7_1ch="7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Zařízení"
|
|||
Mode="Mód"
|
||||
Buffering="Použít vyrovnávací paměť"
|
||||
PixelFormat="Formát pixelů"
|
||||
ChannelFormat="Kanály"
|
||||
ChannelFormat.None="Žádný"
|
||||
ChannelFormat.2_0ch="Stereo"
|
||||
ChannelFormat.5_1ch="5.1"
|
||||
ChannelFormat.5_1chBack="5.1 (zadní)"
|
||||
ChannelFormat.7_1ch="7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
BlackmagicDevice="Blackmagic enhed"
|
||||
BlackmagicDevice="Blackmagic-enhed"
|
||||
Device="Enhed"
|
||||
Mode="Tilstand"
|
||||
Buffering="Brug buffering"
|
||||
PixelFormat="Pixel format"
|
||||
ChannelFormat="Kanal"
|
||||
ChannelFormat.None="Intet"
|
||||
ChannelFormat.2_0ch="2kan"
|
||||
ChannelFormat.5_1ch="5.1kan"
|
||||
ChannelFormat.5_1chBack="5.1kan (bag)"
|
||||
ChannelFormat.7_1ch="7.1kan"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Gerät"
|
|||
Mode="Modus"
|
||||
Buffering="Buffering benutzen"
|
||||
PixelFormat="Pixelformat"
|
||||
ChannelFormat="Kanal"
|
||||
ChannelFormat.None="Keins"
|
||||
ChannelFormat.2_0ch="2 Kanal"
|
||||
ChannelFormat.5_1ch="5.1 Kanal"
|
||||
ChannelFormat.5_1chBack="5.1 Kanal (hinten)"
|
||||
ChannelFormat.7_1ch="7.1 Kanal"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,3 +3,9 @@ Device="Device"
|
|||
Mode="Mode"
|
||||
Buffering="Use Buffering"
|
||||
PixelFormat="Pixel Format"
|
||||
ChannelFormat="Channel"
|
||||
ChannelFormat.None="None"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (Back)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Dispositivo"
|
|||
Mode="Modo"
|
||||
Buffering="Utilizar el almacenamiento en búfer"
|
||||
PixelFormat="Formato de píxel"
|
||||
ChannelFormat="Canal"
|
||||
ChannelFormat.None="Ninguno"
|
||||
ChannelFormat.2_0ch="Estéreo "
|
||||
ChannelFormat.5_1ch="5.1"
|
||||
ChannelFormat.5_1chBack="5.1 (posterior)"
|
||||
ChannelFormat.7_1ch="7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Gailua"
|
|||
Mode="Modua"
|
||||
Buffering="Erabili Bufferreratzea"
|
||||
PixelFormat="Pixel formatua"
|
||||
ChannelFormat="Kanala"
|
||||
ChannelFormat.None="Ezer ez"
|
||||
ChannelFormat.2_0ch="2k"
|
||||
ChannelFormat.5_1ch="5.1k"
|
||||
ChannelFormat.5_1chBack="5.1k (Atzera)"
|
||||
ChannelFormat.7_1ch="7.1k"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Laite"
|
|||
Mode="Tila"
|
||||
Buffering="Käytä puskurointia"
|
||||
PixelFormat="Pikselimuoto"
|
||||
ChannelFormat="Kanava"
|
||||
ChannelFormat.None="Ei mitään"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (Taka)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Périphérique"
|
|||
Mode="Mode"
|
||||
Buffering="Utiliser la mise en mémoire tampon"
|
||||
PixelFormat="Format de pixel"
|
||||
ChannelFormat="Canaux audio"
|
||||
ChannelFormat.None="Aucun"
|
||||
ChannelFormat.2_0ch="canal 2"
|
||||
ChannelFormat.5_1ch="canal 5.1"
|
||||
ChannelFormat.5_1chBack="canal (arrière) 5.1"
|
||||
ChannelFormat.7_1ch="canal 7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Eszköz"
|
|||
Mode="Mód"
|
||||
Buffering="Pufferelés használata"
|
||||
PixelFormat="Képpont formátum"
|
||||
ChannelFormat="Csatorna"
|
||||
ChannelFormat.None="Nincs"
|
||||
ChannelFormat.2_0ch="2cs"
|
||||
ChannelFormat.5_1ch="5.1cs"
|
||||
ChannelFormat.5_1chBack="5.1cs (Hátsó)"
|
||||
ChannelFormat.7_1ch="7.1cs"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
BlackmagicDevice="Blackmagic Device"
|
||||
Device="Dispositivo"
|
||||
Mode="Modalità"
|
||||
Buffering="Usa Buffer"
|
||||
PixelFormat="Formato Pixel"
|
||||
Buffering="Usa buffer"
|
||||
PixelFormat="Formato pixel"
|
||||
ChannelFormat="Canale"
|
||||
ChannelFormat.None="Nessuno"
|
||||
ChannelFormat.2_0ch="2 canali"
|
||||
ChannelFormat.5_1ch="5.1 canali"
|
||||
ChannelFormat.5_1chBack="5.1 canali (retro)"
|
||||
ChannelFormat.7_1ch="7.1 canali"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="デバイス"
|
|||
Mode="モード"
|
||||
Buffering="バッファリングを使用する"
|
||||
PixelFormat="ピクセルフォーマット"
|
||||
ChannelFormat="チャンネル"
|
||||
ChannelFormat.None="未設定"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (背部)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="장치"
|
|||
Mode="방식"
|
||||
Buffering="버퍼링 사용"
|
||||
PixelFormat="픽셀 형식"
|
||||
ChannelFormat="채널"
|
||||
ChannelFormat.None="없음"
|
||||
ChannelFormat.2_0ch="2채널"
|
||||
ChannelFormat.5_1ch="5.1채널"
|
||||
ChannelFormat.5_1chBack="5.1채널 (후면)"
|
||||
ChannelFormat.7_1ch="7.1채널"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Apparaat"
|
|||
Mode="Modus"
|
||||
Buffering="Buffering Gebruiken"
|
||||
PixelFormat="Pixelindeling"
|
||||
ChannelFormat="Kanaal"
|
||||
ChannelFormat.None="Geen"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (Achter)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Urządzenie"
|
|||
Mode="Tryb"
|
||||
Buffering="Użyj buforowania"
|
||||
PixelFormat="Format pikseli"
|
||||
ChannelFormat="Kanały"
|
||||
ChannelFormat.None="Brak"
|
||||
ChannelFormat.2_0ch="2.0"
|
||||
ChannelFormat.5_1ch="5.1"
|
||||
ChannelFormat.5_1chBack="5.1 (tylne)"
|
||||
ChannelFormat.7_1ch="7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Dispositivo"
|
|||
Mode="Modo"
|
||||
Buffering="Utilizar Buffering"
|
||||
PixelFormat="Formato de Pixel"
|
||||
ChannelFormat="Canal"
|
||||
ChannelFormat.None="Nenhum"
|
||||
ChannelFormat.2_0ch="2.0"
|
||||
ChannelFormat.5_1ch="5.1"
|
||||
ChannelFormat.5_1chBack="5.1 (Traseiro)"
|
||||
ChannelFormat.7_1ch="7.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Устройство"
|
|||
Mode="Режим"
|
||||
Buffering="Использовать буферизацию"
|
||||
PixelFormat="Формат пикселей"
|
||||
ChannelFormat="Конфигурация каналов"
|
||||
ChannelFormat.None="Нет"
|
||||
ChannelFormat.2_0ch="2-канальный"
|
||||
ChannelFormat.5_1ch="5.1-канальный"
|
||||
ChannelFormat.5_1chBack="5.1-канальный (Тыловой)"
|
||||
ChannelFormat.7_1ch="7.1-канальный"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Enhet"
|
|||
Mode="Läge"
|
||||
Buffering="Använd buffert"
|
||||
PixelFormat="Bildpunktsformat"
|
||||
ChannelFormat="Kanal"
|
||||
ChannelFormat.None="Ingen"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (bakom)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Aygıt"
|
|||
Mode="Mod"
|
||||
Buffering="Arabelleği Kullan"
|
||||
PixelFormat="Piksel Biçimi"
|
||||
ChannelFormat="Kanal"
|
||||
ChannelFormat.None="Hiçbiri"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (Arka)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="Пристрій"
|
|||
Mode="Режим"
|
||||
Buffering="Увімкнути буферизацію"
|
||||
PixelFormat="Формат пікселів"
|
||||
ChannelFormat="Звук (канали)"
|
||||
ChannelFormat.None="Немає"
|
||||
ChannelFormat.2_0ch="2-канальний"
|
||||
ChannelFormat.5_1ch="5.1-канальний"
|
||||
ChannelFormat.5_1chBack="5.1-канальний (Back)"
|
||||
ChannelFormat.7_1ch="7.1-канальний"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="设备"
|
|||
Mode="模式"
|
||||
Buffering="使用缓冲"
|
||||
PixelFormat="像素格式"
|
||||
ChannelFormat="频道"
|
||||
ChannelFormat.None="无"
|
||||
ChannelFormat.2_0ch="2ch"
|
||||
ChannelFormat.5_1ch="5.1ch"
|
||||
ChannelFormat.5_1chBack="5.1ch (后)"
|
||||
ChannelFormat.7_1ch="7.1ch"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ Device="裝置"
|
|||
Mode="模式"
|
||||
Buffering="使用緩衝"
|
||||
PixelFormat="像素格式"
|
||||
ChannelFormat="聲道"
|
||||
ChannelFormat.None="無"
|
||||
ChannelFormat.2_0ch="雙聲道"
|
||||
ChannelFormat.5_1ch="5.1聲道"
|
||||
ChannelFormat.5_1chBack="5.1聲道(後置環繞喇叭)"
|
||||
ChannelFormat.7_1ch="7.1聲道"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "decklink-device-instance.hpp"
|
||||
#include "audio-repack.hpp"
|
||||
|
||||
#include <util/platform.h>
|
||||
#include <util/threading.h>
|
||||
|
|
@ -8,6 +9,8 @@
|
|||
#define LOG(level, message, ...) blog(level, "%s: " message, \
|
||||
obs_source_get_name(this->decklink->GetSource()), ##__VA_ARGS__)
|
||||
|
||||
#define ISSTEREO(flag) ((flag) == SPEAKERS_STEREO)
|
||||
|
||||
static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
|
|
@ -20,6 +23,36 @@ static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
|
|||
return VIDEO_FORMAT_UYVY;
|
||||
}
|
||||
|
||||
static inline int ConvertChannelFormat(speaker_layout format)
|
||||
{
|
||||
switch (format) {
|
||||
case SPEAKERS_5POINT1:
|
||||
case SPEAKERS_5POINT1_SURROUND:
|
||||
case SPEAKERS_7POINT1:
|
||||
return 8;
|
||||
|
||||
default:
|
||||
case SPEAKERS_STEREO:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format)
|
||||
{
|
||||
switch (format) {
|
||||
case SPEAKERS_5POINT1:
|
||||
case SPEAKERS_5POINT1_SURROUND:
|
||||
return repack_mode_8to6ch_swap23;
|
||||
|
||||
case SPEAKERS_7POINT1:
|
||||
return repack_mode_8ch_swap23;
|
||||
|
||||
default:
|
||||
assert(false && "No repack requested");
|
||||
return (audio_repack_mode_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
DeckLinkDeviceInstance::DeckLinkDeviceInstance(DeckLink *decklink_,
|
||||
DeckLinkDevice *device_) :
|
||||
currentFrame(), currentPacket(), decklink(decklink_), device(device_)
|
||||
|
|
@ -46,9 +79,23 @@ void DeckLinkDeviceInstance::HandleAudioPacket(
|
|||
return;
|
||||
}
|
||||
|
||||
currentPacket.data[0] = (uint8_t *)bytes;
|
||||
currentPacket.frames = (uint32_t)audioPacket->GetSampleFrameCount();
|
||||
currentPacket.timestamp = timestamp;
|
||||
const uint32_t frameCount = (uint32_t)audioPacket->GetSampleFrameCount();
|
||||
currentPacket.frames = frameCount;
|
||||
currentPacket.timestamp = timestamp;
|
||||
|
||||
if (!ISSTEREO(channelFormat)) {
|
||||
if (audioRepacker->repack((uint8_t *)bytes, frameCount) < 0) {
|
||||
LOG(LOG_ERROR, "Failed to convert audio packet data");
|
||||
return;
|
||||
}
|
||||
|
||||
currentPacket.data[0] = (*audioRepacker)->packet_buffer;
|
||||
} else {
|
||||
currentPacket.data[0] = (uint8_t *)bytes;
|
||||
}
|
||||
|
||||
nextAudioTS = timestamp +
|
||||
((uint64_t)frameCount * 1000000000ULL / 48000ULL) + 1;
|
||||
|
||||
obs_source_output_audio(decklink->GetSource(), ¤tPacket);
|
||||
}
|
||||
|
|
@ -78,6 +125,19 @@ void DeckLinkDeviceInstance::HandleVideoFrame(
|
|||
obs_source_output_video(decklink->GetSource(), ¤tFrame);
|
||||
}
|
||||
|
||||
void DeckLinkDeviceInstance::FinalizeStream()
|
||||
{
|
||||
input->SetCallback(nullptr);
|
||||
|
||||
if (audioRepacker != nullptr)
|
||||
{
|
||||
delete audioRepacker;
|
||||
audioRepacker = nullptr;
|
||||
}
|
||||
|
||||
mode = nullptr;
|
||||
}
|
||||
|
||||
bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
||||
{
|
||||
if (mode != nullptr)
|
||||
|
|
@ -93,8 +153,6 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
|||
pixelFormat = decklink->GetPixelFormat();
|
||||
currentFrame.format = ConvertPixelFormat(pixelFormat);
|
||||
|
||||
input->SetCallback(this);
|
||||
|
||||
const BMDDisplayMode displayMode = mode_->GetDisplayMode();
|
||||
|
||||
const HRESULT videoResult = input->EnableVideoInput(displayMode,
|
||||
|
|
@ -102,22 +160,36 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
|||
|
||||
if (videoResult != S_OK) {
|
||||
LOG(LOG_ERROR, "Failed to enable video input");
|
||||
input->SetCallback(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
const HRESULT audioResult = input->EnableAudioInput(
|
||||
bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
|
||||
2);
|
||||
channelFormat = decklink->GetChannelFormat();
|
||||
currentPacket.speakers = channelFormat;
|
||||
|
||||
if (audioResult != S_OK)
|
||||
LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
|
||||
if (channelFormat != SPEAKERS_UNKNOWN) {
|
||||
const int channel = ConvertChannelFormat(channelFormat);
|
||||
const HRESULT audioResult = input->EnableAudioInput(
|
||||
bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
|
||||
channel);
|
||||
|
||||
if (audioResult != S_OK)
|
||||
LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
|
||||
|
||||
if (!ISSTEREO(channelFormat)) {
|
||||
const audio_repack_mode_t repack_mode = ConvertRepackFormat(channelFormat);
|
||||
audioRepacker = new AudioRepacker(repack_mode);
|
||||
}
|
||||
}
|
||||
|
||||
if (input->SetCallback(this) != S_OK) {
|
||||
LOG(LOG_ERROR, "Failed to set callback");
|
||||
FinalizeStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input->StartStreams() != S_OK) {
|
||||
LOG(LOG_ERROR, "Failed to start streams");
|
||||
input->SetCallback(nullptr);
|
||||
input->DisableVideoInput();
|
||||
input->DisableAudioInput();
|
||||
FinalizeStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -135,11 +207,7 @@ bool DeckLinkDeviceInstance::StopCapture(void)
|
|||
GetDevice()->GetDisplayName().c_str());
|
||||
|
||||
input->StopStreams();
|
||||
input->SetCallback(nullptr);
|
||||
input->DisableVideoInput();
|
||||
input->DisableAudioInput();
|
||||
|
||||
mode = nullptr;
|
||||
FinalizeStream();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -154,10 +222,27 @@ HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFrameArrived(
|
|||
BMDTimeValue videoDur = 0;
|
||||
BMDTimeValue audioTS = 0;
|
||||
|
||||
if (videoFrame)
|
||||
if (videoFrame) {
|
||||
videoFrame->GetStreamTime(&videoTS, &videoDur, TIME_BASE);
|
||||
if (audioPacket)
|
||||
audioPacket->GetPacketTime(&audioTS, TIME_BASE);
|
||||
lastVideoTS = (uint64_t)videoTS;
|
||||
}
|
||||
if (audioPacket) {
|
||||
BMDTimeValue newAudioTS = 0;
|
||||
int64_t diff;
|
||||
|
||||
audioPacket->GetPacketTime(&newAudioTS, TIME_BASE);
|
||||
audioTS = newAudioTS + audioOffset;
|
||||
|
||||
diff = (int64_t)audioTS - (int64_t)nextAudioTS;
|
||||
if (diff > 10000000LL) {
|
||||
audioOffset -= diff;
|
||||
audioTS = newAudioTS + audioOffset;
|
||||
|
||||
} else if (diff < -1000000) {
|
||||
audioOffset = 0;
|
||||
audioTS = newAudioTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoFrame && videoTS >= 0)
|
||||
HandleVideoFrame(videoFrame, (uint64_t)videoTS);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "decklink-device.hpp"
|
||||
|
||||
class AudioRepacker;
|
||||
|
||||
class DeckLinkDeviceInstance : public IDeckLinkInputCallback {
|
||||
protected:
|
||||
struct obs_source_frame currentFrame;
|
||||
|
|
@ -12,6 +14,13 @@ protected:
|
|||
BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
|
||||
ComPtr<IDeckLinkInput> input;
|
||||
volatile long refCount = 1;
|
||||
int64_t audioOffset = 0;
|
||||
uint64_t nextAudioTS = 0;
|
||||
uint64_t lastVideoTS = 0;
|
||||
AudioRepacker *audioRepacker = nullptr;
|
||||
speaker_layout channelFormat = SPEAKERS_STEREO;
|
||||
|
||||
void FinalizeStream();
|
||||
|
||||
void HandleAudioPacket(IDeckLinkAudioInputPacket *audioPacket,
|
||||
const uint64_t timestamp);
|
||||
|
|
@ -29,6 +38,7 @@ public:
|
|||
}
|
||||
|
||||
inline BMDPixelFormat GetActivePixelFormat() const {return pixelFormat;}
|
||||
inline speaker_layout GetActiveChannelFormat() const {return channelFormat;}
|
||||
|
||||
inline DeckLinkDeviceMode *GetMode() const {return mode;}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,15 @@ bool DeckLinkDevice::Init()
|
|||
if (result != S_OK)
|
||||
return true;
|
||||
|
||||
int64_t channels;
|
||||
/* Intensity Shuttle for Thunderbolt return 2; however, it supports 8 channels */
|
||||
if (name == "Intensity Shuttle Thunderbolt")
|
||||
maxChannel = 8;
|
||||
else if (attributes->GetInt(BMDDeckLinkMaximumAudioChannels, &channels) == S_OK)
|
||||
maxChannel = (int32_t)channels;
|
||||
else
|
||||
maxChannel = 2;
|
||||
|
||||
/* http://forum.blackmagicdesign.com/viewtopic.php?f=12&t=33967
|
||||
* BMDDeckLinkTopologicalID for older devices
|
||||
* BMDDeckLinkPersistentID for newer ones */
|
||||
|
|
@ -118,3 +127,8 @@ const std::string& DeckLinkDevice::GetName(void) const
|
|||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
int32_t DeckLinkDevice::GetMaxChannel(void) const
|
||||
{
|
||||
return maxChannel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class DeckLinkDevice {
|
|||
std::string name;
|
||||
std::string displayName;
|
||||
std::string hash;
|
||||
int32_t maxChannel;
|
||||
volatile long refCount = 1;
|
||||
|
||||
public:
|
||||
|
|
@ -30,6 +31,7 @@ public:
|
|||
const std::string& GetHash(void) const;
|
||||
const std::vector<DeckLinkDeviceMode *>& GetModes(void) const;
|
||||
const std::string& GetName(void) const;
|
||||
int32_t GetMaxChannel(void) const;
|
||||
|
||||
bool GetInput(IDeckLinkInput **input);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ bool DeckLink::Activate(DeckLinkDevice *device, long long modeId)
|
|||
if (!isActive)
|
||||
return false;
|
||||
if (instance->GetActiveModeId() == modeId &&
|
||||
instance->GetActivePixelFormat() == pixelFormat)
|
||||
instance->GetActivePixelFormat() == pixelFormat &&
|
||||
instance->GetActiveChannelFormat() == channelFormat)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ protected:
|
|||
volatile long activateRefs = 0;
|
||||
std::recursive_mutex deviceMutex;
|
||||
BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
|
||||
speaker_layout channelFormat = SPEAKERS_STEREO;
|
||||
|
||||
void SaveSettings();
|
||||
static void DevicesChanged(void *param, DeckLinkDevice *device,
|
||||
|
|
@ -41,6 +42,11 @@ public:
|
|||
{
|
||||
pixelFormat = format;
|
||||
}
|
||||
inline speaker_layout GetChannelFormat() const {return channelFormat;}
|
||||
inline void SetChannelFormat(speaker_layout format)
|
||||
{
|
||||
channelFormat = format;
|
||||
}
|
||||
|
||||
bool Activate(DeckLinkDevice *device, long long modeId);
|
||||
void Deactivate();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
project(linux-decklink)
|
||||
|
||||
if(DISABLE_DECKLINK)
|
||||
message(STATUS "decklink plugin disabled")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(linux-decklink-sdk_HEADERS
|
||||
decklink-sdk/DeckLinkAPI.h
|
||||
decklink-sdk/DeckLinkAPIConfiguration.h
|
||||
|
|
@ -22,6 +27,8 @@ set(linux-decklink_HEADERS
|
|||
../decklink-device-discovery.hpp
|
||||
../decklink-device.hpp
|
||||
../decklink-device-mode.hpp
|
||||
../audio-repack.h
|
||||
../audio-repack.hpp
|
||||
)
|
||||
|
||||
set(linux-decklink_SOURCES
|
||||
|
|
@ -31,6 +38,7 @@ set(linux-decklink_SOURCES
|
|||
../decklink-device-discovery.cpp
|
||||
../decklink-device.cpp
|
||||
../decklink-device-mode.cpp
|
||||
../audio-repack.c
|
||||
platform.cpp)
|
||||
|
||||
add_library(linux-decklink MODULE
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
project(mac-decklink)
|
||||
|
||||
if(DISABLE_DECKLINK)
|
||||
message(STATUS "decklink plugin disabled")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_library(COREFOUNDATION CoreFoundation)
|
||||
|
||||
include_directories(${COREFOUNDATION})
|
||||
|
|
@ -26,6 +31,8 @@ set(mac-decklink_HEADERS
|
|||
../decklink-device-discovery.hpp
|
||||
../decklink-device.hpp
|
||||
../decklink-device-mode.hpp
|
||||
../audio-repack.h
|
||||
../audio-repack.hpp
|
||||
)
|
||||
|
||||
set(mac-decklink_SOURCES
|
||||
|
|
@ -35,6 +42,7 @@ set(mac-decklink_SOURCES
|
|||
../decklink-device-discovery.cpp
|
||||
../decklink-device.cpp
|
||||
../decklink-device-mode.cpp
|
||||
../audio-repack.c
|
||||
platform.cpp)
|
||||
|
||||
add_library(mac-decklink MODULE
|
||||
|
|
|
|||
|
|
@ -7,17 +7,31 @@
|
|||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("decklink", "en-US")
|
||||
|
||||
#define DEVICE_HASH "device_hash"
|
||||
#define DEVICE_NAME "device_name"
|
||||
#define MODE_ID "mode_id"
|
||||
#define MODE_NAME "mode_name"
|
||||
#define CHANNEL_FORMAT "channel_format"
|
||||
#define PIXEL_FORMAT "pixel_format"
|
||||
#define BUFFERING "buffering"
|
||||
|
||||
#define TEXT_DEVICE obs_module_text("Device")
|
||||
#define TEXT_MODE obs_module_text("Mode")
|
||||
#define TEXT_PIXEL_FORMAT obs_module_text("PixelFormat")
|
||||
#define TEXT_CHANNEL_FORMAT obs_module_text("ChannelFormat")
|
||||
#define TEXT_CHANNEL_FORMAT_NONE obs_module_text("ChannelFormat.None")
|
||||
#define TEXT_CHANNEL_FORMAT_2_0CH obs_module_text("ChannelFormat.2_0ch")
|
||||
#define TEXT_CHANNEL_FORMAT_5_1CH obs_module_text("ChannelFormat.5_1ch")
|
||||
#define TEXT_CHANNEL_FORMAT_5_1CH_BACK obs_module_text("ChannelFormat.5_1chBack")
|
||||
#define TEXT_CHANNEL_FORMAT_7_1CH obs_module_text("ChannelFormat.7_1ch")
|
||||
#define TEXT_BUFFERING obs_module_text("Buffering")
|
||||
|
||||
static DeckLinkDeviceDiscovery *deviceEnum = nullptr;
|
||||
|
||||
static void decklink_enable_buffering(DeckLink *decklink, bool enabled)
|
||||
{
|
||||
obs_source_t *source = decklink->GetSource();
|
||||
uint32_t flags = obs_source_get_flags(source);
|
||||
if (enabled)
|
||||
flags &= ~OBS_SOURCE_FLAG_UNBUFFERED;
|
||||
else
|
||||
flags |= OBS_SOURCE_FLAG_UNBUFFERED;
|
||||
obs_source_set_flags(source, flags);
|
||||
obs_source_set_async_unbuffered(source, !enabled);
|
||||
}
|
||||
|
||||
static void *decklink_create(obs_data_t *settings, obs_source_t *source)
|
||||
|
|
@ -25,7 +39,7 @@ static void *decklink_create(obs_data_t *settings, obs_source_t *source)
|
|||
DeckLink *decklink = new DeckLink(source, deviceEnum);
|
||||
|
||||
decklink_enable_buffering(decklink,
|
||||
obs_data_get_bool(settings, "buffering"));
|
||||
obs_data_get_bool(settings, BUFFERING));
|
||||
|
||||
obs_source_update(source, settings);
|
||||
return decklink;
|
||||
|
|
@ -40,25 +54,29 @@ static void decklink_destroy(void *data)
|
|||
static void decklink_update(void *data, obs_data_t *settings)
|
||||
{
|
||||
DeckLink *decklink = (DeckLink *)data;
|
||||
const char *hash = obs_data_get_string(settings, "device_hash");
|
||||
long long id = obs_data_get_int(settings, "mode_id");
|
||||
BMDPixelFormat format = (BMDPixelFormat)obs_data_get_int(settings,
|
||||
"pixel_format");
|
||||
const char *hash = obs_data_get_string(settings, DEVICE_HASH);
|
||||
long long id = obs_data_get_int(settings, MODE_ID);
|
||||
BMDPixelFormat pixelFormat = (BMDPixelFormat)obs_data_get_int(settings,
|
||||
PIXEL_FORMAT);
|
||||
speaker_layout channelFormat = (speaker_layout)obs_data_get_int(settings,
|
||||
CHANNEL_FORMAT);
|
||||
|
||||
decklink_enable_buffering(decklink,
|
||||
obs_data_get_bool(settings, "buffering"));
|
||||
obs_data_get_bool(settings, BUFFERING));
|
||||
|
||||
ComPtr<DeckLinkDevice> device;
|
||||
device.Set(deviceEnum->FindByHash(hash));
|
||||
|
||||
decklink->SetPixelFormat(format);
|
||||
decklink->SetPixelFormat(pixelFormat);
|
||||
decklink->SetChannelFormat(channelFormat);
|
||||
decklink->Activate(device, id);
|
||||
}
|
||||
|
||||
static void decklink_get_defaults(obs_data_t *settings)
|
||||
{
|
||||
obs_data_set_default_bool(settings, "buffering", true);
|
||||
obs_data_set_default_int(settings, "pixel_format", bmdFormat8BitYUV);
|
||||
obs_data_set_default_bool(settings, BUFFERING, true);
|
||||
obs_data_set_default_int(settings, PIXEL_FORMAT, bmdFormat8BitYUV);
|
||||
obs_data_set_default_int(settings, CHANNEL_FORMAT, SPEAKERS_STEREO);
|
||||
}
|
||||
|
||||
static const char *decklink_get_name(void*)
|
||||
|
|
@ -69,10 +87,10 @@ static const char *decklink_get_name(void*)
|
|||
static bool decklink_device_changed(obs_properties_t *props,
|
||||
obs_property_t *list, obs_data_t *settings)
|
||||
{
|
||||
const char *name = obs_data_get_string(settings, "device_name");
|
||||
const char *hash = obs_data_get_string(settings, "device_hash");
|
||||
const char *mode = obs_data_get_string(settings, "mode_name");
|
||||
long long modeId = obs_data_get_int(settings, "mode_id");
|
||||
const char *name = obs_data_get_string(settings, DEVICE_NAME);
|
||||
const char *hash = obs_data_get_string(settings, DEVICE_HASH);
|
||||
const char *mode = obs_data_get_string(settings, MODE_NAME);
|
||||
long long modeId = obs_data_get_int(settings, MODE_ID);
|
||||
|
||||
size_t itemCount = obs_property_list_item_count(list);
|
||||
bool itemFound = false;
|
||||
|
|
@ -90,25 +108,41 @@ static bool decklink_device_changed(obs_properties_t *props,
|
|||
obs_property_list_item_disable(list, 0, true);
|
||||
}
|
||||
|
||||
list = obs_properties_get(props, "mode_id");
|
||||
obs_property_t *modeList = obs_properties_get(props, MODE_ID);
|
||||
obs_property_t *channelList = obs_properties_get(props, CHANNEL_FORMAT);
|
||||
|
||||
obs_property_list_clear(list);
|
||||
obs_property_list_clear(modeList);
|
||||
|
||||
obs_property_list_clear(channelList);
|
||||
obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_NONE,
|
||||
SPEAKERS_UNKNOWN);
|
||||
obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_2_0CH,
|
||||
SPEAKERS_STEREO);
|
||||
|
||||
ComPtr<DeckLinkDevice> device;
|
||||
device.Set(deviceEnum->FindByHash(hash));
|
||||
|
||||
if (!device) {
|
||||
obs_property_list_add_int(list, mode, modeId);
|
||||
obs_property_list_item_disable(list, 0, true);
|
||||
obs_property_list_add_int(modeList, mode, modeId);
|
||||
obs_property_list_item_disable(modeList, 0, true);
|
||||
} else {
|
||||
const std::vector<DeckLinkDeviceMode*> &modes =
|
||||
device->GetModes();
|
||||
|
||||
for (DeckLinkDeviceMode *mode : modes) {
|
||||
obs_property_list_add_int(list,
|
||||
obs_property_list_add_int(modeList,
|
||||
mode->GetName().c_str(),
|
||||
mode->GetId());
|
||||
}
|
||||
|
||||
if (device->GetMaxChannel() >= 8) {
|
||||
obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_5_1CH,
|
||||
SPEAKERS_5POINT1);
|
||||
obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_5_1CH_BACK,
|
||||
SPEAKERS_5POINT1_SURROUND);
|
||||
obs_property_list_add_int(channelList, TEXT_CHANNEL_FORMAT_7_1CH,
|
||||
SPEAKERS_7POINT1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -132,26 +166,30 @@ static obs_properties_t *decklink_get_properties(void *data)
|
|||
{
|
||||
obs_properties_t *props = obs_properties_create();
|
||||
|
||||
obs_property_t *list = obs_properties_add_list(props, "device_hash",
|
||||
obs_module_text("Device"), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_t *list = obs_properties_add_list(props, DEVICE_HASH,
|
||||
TEXT_DEVICE, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_set_modified_callback(list, decklink_device_changed);
|
||||
|
||||
fill_out_devices(list);
|
||||
|
||||
list = obs_properties_add_list(props, "mode_id",
|
||||
obs_module_text("Mode"), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
list = obs_properties_add_list(props, MODE_ID, TEXT_MODE,
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
|
||||
list = obs_properties_add_list(props, "pixel_format",
|
||||
obs_module_text("PixelFormat"), OBS_COMBO_TYPE_LIST,
|
||||
list = obs_properties_add_list(props, PIXEL_FORMAT,
|
||||
TEXT_PIXEL_FORMAT, OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
|
||||
obs_property_list_add_int(list, "8-bit YUV", bmdFormat8BitYUV);
|
||||
obs_property_list_add_int(list, "8-bit BGRA", bmdFormat8BitBGRA);
|
||||
|
||||
obs_properties_add_bool(props, "buffering",
|
||||
obs_module_text("Buffering"));
|
||||
list = obs_properties_add_list(props, CHANNEL_FORMAT,
|
||||
TEXT_CHANNEL_FORMAT, OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_list_add_int(list, TEXT_CHANNEL_FORMAT_NONE,
|
||||
SPEAKERS_UNKNOWN);
|
||||
obs_property_list_add_int(list, TEXT_CHANNEL_FORMAT_2_0CH,
|
||||
SPEAKERS_STEREO);
|
||||
|
||||
obs_properties_add_bool(props, BUFFERING, TEXT_BUFFERING);
|
||||
|
||||
UNUSED_PARAMETER(data);
|
||||
return props;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
project(win-decklink)
|
||||
|
||||
if(DISABLE_DECKLINK)
|
||||
message(STATUS "decklink plugin disabled")
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(IDLFileHelper)
|
||||
|
||||
set(win-decklink-sdk_IDLS
|
||||
|
|
@ -17,6 +22,8 @@ set(win-decklink_HEADERS
|
|||
../decklink-device-discovery.hpp
|
||||
../decklink-device.hpp
|
||||
../decklink-device-mode.hpp
|
||||
../audio-repack.h
|
||||
../audio-repack.hpp
|
||||
)
|
||||
|
||||
set(win-decklink_SOURCES
|
||||
|
|
@ -26,6 +33,7 @@ set(win-decklink_SOURCES
|
|||
../decklink-device-discovery.cpp
|
||||
../decklink-device.cpp
|
||||
../decklink-device-mode.cpp
|
||||
../audio-repack.c
|
||||
platform.cpp)
|
||||
|
||||
add_idl_files(win-decklink-sdk_GENERATED_FILES
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue