Merge AJA audio/video source/sink plugin

Original location is https://github.com/centricular/gst-aja
This commit is contained in:
Sebastian Dröge 2023-10-26 09:35:52 +03:00
commit d2d947380e
19 changed files with 8330 additions and 0 deletions

182
.clang-format Normal file
View file

@ -0,0 +1,182 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
...

View file

@ -0,0 +1,202 @@
# GStreamer AJA source/sink plugin
[GStreamer](https://gstreamer.freedesktop.org/) plugin for
[AJA](https://www.aja.com) capture and output cards.
This plugin requires the AJA NTV2 SDK version 16 or newer.
The location of the SDK can be configured via the `aja-sdk-dir` meson option.
If no location is given then the NTV2 SDK from
[GitHub](https://github.com/aja-video/ntv2.git) is compiled as a meson
subproject as part of the plugin.
## Example usage
Capture 1080p30 audio/video and display it locally
```sh
gst-launch-1.0 ajasrc video-format=1080p-3000 ! ajasrcdemux name=d \
d.video ! queue max-size-bytes=0 max-size-buffers=0 max-size-time=1000000000 ! videoconvert ! autovideosink \
d.audio ! queue max-size-bytes=0 max-size-buffers=0 max-size-time=1000000000 ! audioconvert ! audioresample ! autoaudiosink
```
Output a 1080p2997 test audio/video stream
```sh
gst-launch-1.0 videotestsrc pattern=ball ! video/x-raw,format=v210,width=1920,height=1080,framerate=30000/1001,interlace-mode=progressive ! timeoverlay ! timecodestamper ! combiner.video \
audiotestsrc freq=440 ! audio/x-raw,format=S32LE,rate=48000,channels=16 ! audiobuffersplit output-buffer-duration=1/30 ! combiner.audio \
ajasinkcombiner name=combiner ! ajasink channel=0
```
Capture 1080p30 audio/video and directly output it again on the same card
```sh
gst-launch-1.0 ajasrc video-format=1080p-3000 channel=1 input-source=sdi-1 audio-system=2 ! ajasrcdemux name=d \
d.video ! queue max-size-bytes=0 max-size-buffers=0 max-size-time=1000000000 ! c.video \
d.audio ! queue max-size-bytes=0 max-size-buffers=0 max-size-time=1000000000 ! c.audio \
ajasinkcombiner name=c ! ajasink channel=0 reference-source=input-1
```
## Configuration
### Source
```
audio-source : Audio source to use
flags: readable, writable
Enum "GstAjaAudioSource" Default: 0, "Embedded"
(0): Embedded - embedded
(1): AES - aes
(2): Analog - analog
(3): HDMI - hdmi
(4): Microphone - mic
audio-system : Audio system to use
flags: readable, writable
Enum "GstAjaAudioSystem" Default: 0, "Auto (based on selected channel)"
(0): Auto (based on selected channel) - auto
(1): Audio system 1 - 1
(2): Audio system 2 - 2
(3): Audio system 3 - 3
(4): Audio system 4 - 4
(5): Audio system 5 - 5
(6): Audio system 6 - 6
(7): Audio system 7 - 7
(8): Audio system 8 - 8
capture-cpu-core : Sets the affinity of the capture thread to this CPU core (-1=disabled)
flags: readable, writable
Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295
channel : Channel to use
flags: readable, writable
Unsigned Integer. Range: 0 - 7 Default: 0
device-identifier : Input device instance to use
flags: readable, writable
String. Default: "0"
input-source : Input source to use
flags: readable, writable
Enum "GstAjaInputSource" Default: 0, "Auto (based on selected channel)"
(0): Auto (based on selected channel) - auto
(1): Analog Input 1 - analog-1
(6): SDI Input 1 - sdi-1
(7): SDI Input 2 - sdi-2
(8): SDI Input 3 - sdi-3
(9): SDI Input 4 - sdi-4
(10): SDI Input 5 - sdi-5
(11): SDI Input 6 - sdi-6
(12): SDI Input 7 - sdi-7
(13): SDI Input 8 - sdi-8
(2): HDMI Input 1 - hdmi-1
(3): HDMI Input 2 - hdmi-2
(4): HDMI Input 3 - hdmi-3
(5): HDMI Input 4 - hdmi-4
queue-size : Size of internal queue in number of video frames. Half of this is allocated as device buffers and equal to the latency.
flags: readable, writable
Unsigned Integer. Range: 1 - 2147483647 Default: 16
reference-source : Reference source to use
flags: readable, writable
Enum "GstAjaReferenceSource" Default: 1, "Freerun"
(0): Auto - auto
(1): Freerun - freerun
(2): External - external
(3): SDI Input 1 - input-1
(4): SDI Input 2 - input-2
(5): SDI Input 3 - input-3
(6): SDI Input 4 - input-4
(7): SDI Input 5 - input-5
(8): SDI Input 6 - input-6
(9): SDI Input 7 - input-7
(10): SDI Input 8 - input-8
timecode-index : Timecode index to use
flags: readable, writable
Enum "GstAjaTimecodeIndex" Default: 0, "Embedded SDI ATC LTC"
(0): Embedded SDI VITC - vitc
(0): Embedded SDI ATC LTC - atc-ltc
(2): Analog LTC 1 - ltc-1
(3): Analog LTC 2 - ltc-2
video-format : Video format to use
flags: readable, writable
Enum "GstAjaVideoFormat" Default: 0, "1080i 5000"
(0): 1080i 5000 - 1080i-5000
(1): 1080i 5994 - 1080i-5994
(2): 1080i 6000 - 1080i-6000
(3): 720p 5994 - 720p-5994
(4): 720p 6000 - 720p-6000
(5): 1080p 2997 - 1080p-2997
(6): 1080p 3000 - 1080p-3000
(7): 1080p 2500 - 1080p-2500
(8): 1080p 2398 - 1080p-2398
(9): 1080p 2400 - 1080p-2400
(10): 720p 5000 - 720p-5000
(11): 720p 2398 - 720p-2398
(12): 720p 2500 - 720p-2500
(13): 1080p 5000 A - 1080p-5000-a
(14): 1080p 5994 A - 1080p-5994-a
(15): 1080p 6000 A - 1080p-6000-a
(16): 625 5000 - 625-5000
(17): 525 5994 - 525-5994
(18): 525 2398 - 525-2398
(19): 525 2400 - 525-2400
```
### Sink
```
audio-system : Audio system to use
flags: readable, writable
Enum "GstAjaAudioSystem" Default: 0, "Auto (based on selected channel)"
(0): Auto (based on selected channel) - auto
(1): Audio system 1 - 1
(2): Audio system 2 - 2
(3): Audio system 3 - 3
(4): Audio system 4 - 4
(5): Audio system 5 - 5
(6): Audio system 6 - 6
(7): Audio system 7 - 7
(8): Audio system 8 - 8
channel : Channel to use
flags: readable, writable
Unsigned Integer. Range: 0 - 7 Default: 0
device-identifier : Input device instance to use
flags: readable, writable
String. Default: "0"
output-cpu-core : Sets the affinity of the output thread to this CPU core (-1=disabled)
flags: readable, writable
Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295
output-destination : Output destination to use
flags: readable, writable
Enum "GstAjaOutputDestination" Default: 0, "Auto (based on selected channel)"
(0): Auto (based on selected channel) - auto
(1): Analog Output - analog
(2): SDI Output 1 - sdi-1
(3): SDI Output 2 - sdi-2
(4): SDI Output 3 - sdi-3
(5): SDI Output 4 - sdi-4
(6): SDI Output 5 - sdi-5
(7): SDI Output 6 - sdi-6
(8): SDI Output 7 - sdi-7
(9): SDI Output 8 - sdi-8
(10): HDMI Output - hdmi
queue-size : Size of internal queue in number of video frames. Half of this is allocated as device buffers and equal to the latency.
flags: readable, writable
Unsigned Integer. Range: 1 - 2147483647 Default: 16
reference-source : Reference source to use
flags: readable, writable
Enum "GstAjaReferenceSource" Default: 0, "Auto"
(0): Auto - auto
(1): Freerun - freerun
(2): External - external
(3): SDI Input 1 - input-1
(4): SDI Input 2 - input-2
(5): SDI Input 3 - input-3
(6): SDI Input 4 - input-4
(7): SDI Input 5 - input-5
(8): SDI Input 6 - input-6
(9): SDI Input 7 - input-7
(10): SDI Input 8 - input-8
timecode-index : Timecode index to use
flags: readable, writable
Enum "GstAjaTimecodeIndex" Default: 0, "Embedded SDI ATC LTC"
(0): Embedded SDI VITC - vitc
(0): Embedded SDI ATC LTC - atc-ltc
(2): Analog LTC 1 - ltc-1
(3): Analog LTC 2 - ltc-2
```

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,354 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <ajabase/common/types.h>
#include <ajabase/system/memory.h>
#include <ajabase/system/thread.h>
#include <ajantv2/includes/ntv2card.h>
#include <ajantv2/includes/ntv2devicefeatures.h>
#include <ajantv2/includes/ntv2devicescanner.h>
#include <ajantv2/includes/ntv2enums.h>
#include <ajantv2/includes/ntv2signalrouter.h>
#include <gst/base/base.h>
#include <gst/gst.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
typedef struct {
GstMeta meta;
GstBuffer *buffer;
} GstAjaAudioMeta;
G_GNUC_INTERNAL
GType gst_aja_audio_meta_api_get_type(void);
#define GST_AJA_AUDIO_META_API_TYPE (gst_aja_audio_meta_api_get_type())
G_GNUC_INTERNAL
const GstMetaInfo *gst_aja_audio_meta_get_info(void);
#define GST_AJA_AUDIO_META_INFO (gst_aja_audio_meta_get_info())
#define gst_buffer_get_aja_audio_meta(b) \
((GstAjaAudioMeta *)gst_buffer_get_meta((b), GST_AJA_AUDIO_META_API_TYPE))
G_GNUC_INTERNAL
GstAjaAudioMeta *gst_buffer_add_aja_audio_meta(GstBuffer *buffer,
GstBuffer *audio_buffer);
typedef struct {
CNTV2Card *device;
} GstAjaNtv2Device;
G_GNUC_INTERNAL
GstAjaNtv2Device *gst_aja_ntv2_device_obtain(const gchar *device_identifier);
G_GNUC_INTERNAL
GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device);
G_GNUC_INTERNAL
void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device);
G_GNUC_INTERNAL
gint gst_aja_ntv2_device_find_unallocated_frames(GstAjaNtv2Device *device,
NTV2Channel channel,
guint frame_count);
#define GST_AJA_ALLOCATOR_MEMTYPE "aja"
#define GST_TYPE_AJA_ALLOCATOR (gst_aja_allocator_get_type())
#define GST_AJA_ALLOCATOR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_ALLOCATOR, GstAjaAllocator))
#define GST_AJA_ALLOCATOR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AJA_ALLOCATOR, \
GstAjaAllocatorClass))
#define GST_IS_Aja_ALLOCATOR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AJA_ALLOCATOR))
#define GST_IS_Aja_ALLOCATOR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AJA_ALLOCATOR))
#define GST_AJA_ALLOCATOR_CAST(obj) ((GstAjaAllocator *)(obj))
typedef struct _GstAjaAllocator GstAjaAllocator;
typedef struct _GstAjaAllocatorClass GstAjaAllocatorClass;
struct _GstAjaAllocator {
GstAllocator allocator;
GstAjaNtv2Device *device;
GstQueueArray *freed_mems;
};
struct _GstAjaAllocatorClass {
GstAllocatorClass parent_class;
};
G_GNUC_INTERNAL
GType gst_aja_allocator_get_type(void);
G_GNUC_INTERNAL
GstAllocator *gst_aja_allocator_new(GstAjaNtv2Device *device);
typedef enum {
GST_AJA_AUDIO_SYSTEM_AUTO,
GST_AJA_AUDIO_SYSTEM_1,
GST_AJA_AUDIO_SYSTEM_2,
GST_AJA_AUDIO_SYSTEM_3,
GST_AJA_AUDIO_SYSTEM_4,
GST_AJA_AUDIO_SYSTEM_5,
GST_AJA_AUDIO_SYSTEM_6,
GST_AJA_AUDIO_SYSTEM_7,
GST_AJA_AUDIO_SYSTEM_8,
} GstAjaAudioSystem;
#define GST_TYPE_AJA_AUDIO_SYSTEM (gst_aja_audio_system_get_type())
G_GNUC_INTERNAL
GType gst_aja_audio_system_get_type(void);
typedef enum {
GST_AJA_OUTPUT_DESTINATION_AUTO,
GST_AJA_OUTPUT_DESTINATION_ANALOG,
GST_AJA_OUTPUT_DESTINATION_SDI1,
GST_AJA_OUTPUT_DESTINATION_SDI2,
GST_AJA_OUTPUT_DESTINATION_SDI3,
GST_AJA_OUTPUT_DESTINATION_SDI4,
GST_AJA_OUTPUT_DESTINATION_SDI5,
GST_AJA_OUTPUT_DESTINATION_SDI6,
GST_AJA_OUTPUT_DESTINATION_SDI7,
GST_AJA_OUTPUT_DESTINATION_SDI8,
GST_AJA_OUTPUT_DESTINATION_HDMI,
} GstAjaOutputDestination;
#define GST_TYPE_AJA_OUTPUT_DESTINATION (gst_aja_output_destination_get_type())
G_GNUC_INTERNAL
GType gst_aja_output_destination_get_type(void);
typedef enum {
GST_AJA_REFERENCE_SOURCE_AUTO,
GST_AJA_REFERENCE_SOURCE_FREERUN,
GST_AJA_REFERENCE_SOURCE_EXTERNAL,
GST_AJA_REFERENCE_SOURCE_INPUT_1,
GST_AJA_REFERENCE_SOURCE_INPUT_2,
GST_AJA_REFERENCE_SOURCE_INPUT_3,
GST_AJA_REFERENCE_SOURCE_INPUT_4,
GST_AJA_REFERENCE_SOURCE_INPUT_5,
GST_AJA_REFERENCE_SOURCE_INPUT_6,
GST_AJA_REFERENCE_SOURCE_INPUT_7,
GST_AJA_REFERENCE_SOURCE_INPUT_8,
} GstAjaReferenceSource;
#define GST_TYPE_AJA_REFERENCE_SOURCE (gst_aja_reference_source_get_type())
G_GNUC_INTERNAL
GType gst_aja_reference_source_get_type(void);
typedef enum {
GST_AJA_INPUT_SOURCE_AUTO,
GST_AJA_INPUT_SOURCE_ANALOG1,
GST_AJA_INPUT_SOURCE_HDMI1,
GST_AJA_INPUT_SOURCE_HDMI2,
GST_AJA_INPUT_SOURCE_HDMI3,
GST_AJA_INPUT_SOURCE_HDMI4,
GST_AJA_INPUT_SOURCE_SDI1,
GST_AJA_INPUT_SOURCE_SDI2,
GST_AJA_INPUT_SOURCE_SDI3,
GST_AJA_INPUT_SOURCE_SDI4,
GST_AJA_INPUT_SOURCE_SDI5,
GST_AJA_INPUT_SOURCE_SDI6,
GST_AJA_INPUT_SOURCE_SDI7,
GST_AJA_INPUT_SOURCE_SDI8,
} GstAjaInputSource;
#define GST_TYPE_AJA_INPUT_SOURCE (gst_aja_input_source_get_type())
G_GNUC_INTERNAL
GType gst_aja_input_source_get_type(void);
typedef enum {
GST_AJA_SDI_MODE_SINGLE_LINK,
GST_AJA_SDI_MODE_QUAD_LINK_SQD,
GST_AJA_SDI_MODE_QUAD_LINK_TSI,
} GstAjaSdiMode;
#define GST_TYPE_AJA_SDI_MODE (gst_aja_sdi_mode_get_type())
G_GNUC_INTERNAL
GType gst_aja_sdi_mode_get_type(void);
typedef enum {
GST_AJA_VIDEO_FORMAT_INVALID = -1,
GST_AJA_VIDEO_FORMAT_AUTO,
GST_AJA_VIDEO_FORMAT_1080i_5000,
GST_AJA_VIDEO_FORMAT_1080i_5994,
GST_AJA_VIDEO_FORMAT_1080i_6000,
GST_AJA_VIDEO_FORMAT_720p_5994,
GST_AJA_VIDEO_FORMAT_720p_6000,
GST_AJA_VIDEO_FORMAT_1080psf_2398,
GST_AJA_VIDEO_FORMAT_1080psf_2400,
GST_AJA_VIDEO_FORMAT_1080p_2997,
GST_AJA_VIDEO_FORMAT_1080p_3000,
GST_AJA_VIDEO_FORMAT_1080p_2500,
GST_AJA_VIDEO_FORMAT_1080p_2398,
GST_AJA_VIDEO_FORMAT_1080p_2400,
GST_AJA_VIDEO_FORMAT_720p_5000,
GST_AJA_VIDEO_FORMAT_1080p_5000_A,
GST_AJA_VIDEO_FORMAT_1080p_5994_A,
GST_AJA_VIDEO_FORMAT_1080p_6000_A,
GST_AJA_VIDEO_FORMAT_720p_2398,
GST_AJA_VIDEO_FORMAT_720p_2500,
GST_AJA_VIDEO_FORMAT_1080psf_2500_2,
GST_AJA_VIDEO_FORMAT_1080psf_2997_2,
GST_AJA_VIDEO_FORMAT_1080psf_3000_2,
GST_AJA_VIDEO_FORMAT_625_5000,
GST_AJA_VIDEO_FORMAT_525_5994,
GST_AJA_VIDEO_FORMAT_525_2398,
GST_AJA_VIDEO_FORMAT_525_2400,
GST_AJA_VIDEO_FORMAT_1080p_DCI_2398,
GST_AJA_VIDEO_FORMAT_1080p_DCI_2400,
GST_AJA_VIDEO_FORMAT_1080p_DCI_2500,
GST_AJA_VIDEO_FORMAT_1080p_DCI_2997,
GST_AJA_VIDEO_FORMAT_1080p_DCI_3000,
GST_AJA_VIDEO_FORMAT_1080p_DCI_5000_A,
GST_AJA_VIDEO_FORMAT_1080p_DCI_5994_A,
GST_AJA_VIDEO_FORMAT_1080p_DCI_6000_A,
GST_AJA_VIDEO_FORMAT_2160p_2398,
GST_AJA_VIDEO_FORMAT_2160p_2400,
GST_AJA_VIDEO_FORMAT_2160p_2500,
GST_AJA_VIDEO_FORMAT_2160p_2997,
GST_AJA_VIDEO_FORMAT_2160p_3000,
GST_AJA_VIDEO_FORMAT_2160p_5000,
GST_AJA_VIDEO_FORMAT_2160p_5994,
GST_AJA_VIDEO_FORMAT_2160p_6000,
GST_AJA_VIDEO_FORMAT_2160p_DCI_2398,
GST_AJA_VIDEO_FORMAT_2160p_DCI_2400,
GST_AJA_VIDEO_FORMAT_2160p_DCI_2500,
GST_AJA_VIDEO_FORMAT_2160p_DCI_2997,
GST_AJA_VIDEO_FORMAT_2160p_DCI_3000,
GST_AJA_VIDEO_FORMAT_2160p_DCI_5000,
GST_AJA_VIDEO_FORMAT_2160p_DCI_5994,
GST_AJA_VIDEO_FORMAT_2160p_DCI_6000,
GST_AJA_VIDEO_FORMAT_4320p_2398,
GST_AJA_VIDEO_FORMAT_4320p_2400,
GST_AJA_VIDEO_FORMAT_4320p_2500,
GST_AJA_VIDEO_FORMAT_4320p_2997,
GST_AJA_VIDEO_FORMAT_4320p_3000,
GST_AJA_VIDEO_FORMAT_4320p_5000,
GST_AJA_VIDEO_FORMAT_4320p_5994,
GST_AJA_VIDEO_FORMAT_4320p_6000,
GST_AJA_VIDEO_FORMAT_4320p_DCI_2398,
GST_AJA_VIDEO_FORMAT_4320p_DCI_2400,
GST_AJA_VIDEO_FORMAT_4320p_DCI_2500,
GST_AJA_VIDEO_FORMAT_4320p_DCI_2997,
GST_AJA_VIDEO_FORMAT_4320p_DCI_3000,
GST_AJA_VIDEO_FORMAT_4320p_DCI_5000,
GST_AJA_VIDEO_FORMAT_4320p_DCI_5994,
GST_AJA_VIDEO_FORMAT_4320p_DCI_6000,
} GstAjaVideoFormat;
#define GST_TYPE_AJA_VIDEO_FORMAT (gst_aja_video_format_get_type())
G_GNUC_INTERNAL
GType gst_aja_video_format_get_type(void);
typedef enum {
GST_AJA_AUDIO_SOURCE_EMBEDDED,
GST_AJA_AUDIO_SOURCE_AES,
GST_AJA_AUDIO_SOURCE_ANALOG,
GST_AJA_AUDIO_SOURCE_HDMI,
GST_AJA_AUDIO_SOURCE_MIC,
} GstAjaAudioSource;
#define GST_TYPE_AJA_AUDIO_SOURCE (gst_aja_audio_source_get_type())
G_GNUC_INTERNAL
GType gst_aja_audio_source_get_type(void);
typedef enum {
GST_AJA_EMBEDDED_AUDIO_INPUT_AUTO,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO1,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO2,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO3,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO4,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO5,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO6,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO7,
GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO8,
} GstAjaEmbeddedAudioInput;
#define GST_TYPE_AJA_EMBEDDED_AUDIO_INPUT \
(gst_aja_embedded_audio_input_get_type())
G_GNUC_INTERNAL
GType gst_aja_embedded_audio_input_get_type(void);
typedef enum {
GST_AJA_TIMECODE_INDEX_VITC,
GST_AJA_TIMECODE_INDEX_ATC_LTC,
GST_AJA_TIMECODE_INDEX_LTC1,
GST_AJA_TIMECODE_INDEX_LTC2,
} GstAjaTimecodeIndex;
#define GST_TYPE_AJA_TIMECODE_INDEX (gst_aja_timecode_index_get_type())
G_GNUC_INTERNAL
GType gst_aja_timecode_index_get_type(void);
typedef enum {
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_AND_CEA608,
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_OR_CEA608,
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA608_OR_CEA708,
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_ONLY,
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA608_ONLY,
GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_NONE,
} GstAjaClosedCaptionCaptureMode;
#define GST_TYPE_AJA_CLOSED_CAPTION_CAPTURE_MODE \
(gst_aja_closed_caption_capture_mode_get_type())
G_GNUC_INTERNAL
GType gst_aja_closed_caption_capture_mode_get_type(void);
G_GNUC_INTERNAL
void gst_aja_common_init(void);
G_END_DECLS
class ShmMutexLocker {
public:
ShmMutexLocker();
~ShmMutexLocker();
};
G_GNUC_INTERNAL
GstCaps *gst_ntv2_supported_caps(NTV2DeviceID device_id);
G_GNUC_INTERNAL
GstCaps *gst_ntv2_video_format_to_caps(NTV2VideoFormat format);
G_GNUC_INTERNAL
bool gst_video_info_from_ntv2_video_format(GstVideoInfo *info,
NTV2VideoFormat format);
G_GNUC_INTERNAL
NTV2VideoFormat gst_ntv2_video_format_from_caps(const GstCaps *caps, bool quad);
G_GNUC_INTERNAL
GstCaps *gst_aja_video_format_to_caps(GstAjaVideoFormat format);
G_GNUC_INTERNAL
bool gst_video_info_from_aja_video_format(GstVideoInfo *info,
GstAjaVideoFormat format);
G_GNUC_INTERNAL
GstAjaVideoFormat gst_aja_video_format_from_caps(const GstCaps *caps);
G_GNUC_INTERNAL
GstAjaVideoFormat gst_aja_video_format_from_ntv2_format(NTV2VideoFormat format);
G_GNUC_INTERNAL
NTV2VideoFormat gst_ntv2_video_format_from_aja_format(GstAjaVideoFormat format,
bool quad);
G_GNUC_INTERNAL
bool gst_ntv2_video_format_is_quad(NTV2VideoFormat format);

View file

@ -0,0 +1,170 @@
/*
* Copyright (C) 2019 Mathieu Duponchelle <mathieu@centricular.com>
* Copyright (C) 2019,2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstajacommon.h"
#include "gstajadeviceprovider.h"
static GstDevice *gst_aja_device_new(NTV2DeviceInfo &device, gboolean video);
G_DEFINE_TYPE(GstAjaDeviceProvider, gst_aja_device_provider,
GST_TYPE_DEVICE_PROVIDER);
static void gst_aja_device_provider_init(GstAjaDeviceProvider *self) {}
static GList *gst_aja_device_provider_probe(GstDeviceProvider *provider) {
GList *ret = NULL;
CNTV2DeviceScanner scanner;
NTV2DeviceInfoList devices = scanner.GetDeviceInfoList();
for (NTV2DeviceInfoList::iterator it = devices.begin(); it != devices.end();
it++) {
// Skip non-input / non-output devices
if (it->numVidInputs == 0 && it->numVidOutputs == 0) continue;
if (it->numVidInputs > 0)
ret = g_list_prepend(ret, gst_aja_device_new(*it, TRUE));
if (it->numVidOutputs > 0)
ret = g_list_prepend(ret, gst_aja_device_new(*it, FALSE));
}
ret = g_list_reverse(ret);
return ret;
}
static void gst_aja_device_provider_class_init(
GstAjaDeviceProviderClass *klass) {
GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS(klass);
dm_class->probe = GST_DEBUG_FUNCPTR(gst_aja_device_provider_probe);
gst_device_provider_class_set_static_metadata(
dm_class, "AJA Device Provider", "Source/Audio/Video",
"List and provides AJA capture devices",
"Sebastian Dröge <sebastian@centricular.com>");
}
G_DEFINE_TYPE(GstAjaDevice, gst_aja_device, GST_TYPE_DEVICE);
static void gst_aja_device_init(GstAjaDevice *self) {}
static GstElement *gst_aja_device_create_element(GstDevice *device,
const gchar *name) {
GstAjaDevice *self = GST_AJA_DEVICE(device);
GstElement *ret = NULL;
if (self->is_capture) {
ret = gst_element_factory_make("ajasrc", name);
} else {
ret = gst_element_factory_make("ajasink", name);
}
if (ret) {
gchar *device_identifier = g_strdup_printf("%u", self->device_index);
g_object_set(ret, "device-identifier", device_identifier, NULL);
g_free(device_identifier);
}
return ret;
}
static void gst_aja_device_class_init(GstAjaDeviceClass *klass) {
GstDeviceClass *gst_device_class = GST_DEVICE_CLASS(klass);
gst_device_class->create_element =
GST_DEBUG_FUNCPTR(gst_aja_device_create_element);
}
static GstDevice *gst_aja_device_new(NTV2DeviceInfo &device,
gboolean is_capture) {
GstDevice *ret;
gchar *display_name;
const gchar *device_class;
GstCaps *caps = NULL;
GstStructure *properties;
device_class = is_capture ? "Audio/Video/Source" : "Audio/Video/Sink";
display_name = g_strdup_printf("AJA %s (%s)", device.deviceIdentifier.c_str(),
is_capture ? "Source" : "Sink");
caps = gst_ntv2_supported_caps(device.deviceID);
properties = gst_structure_new_empty("properties");
gst_structure_set(
properties, "device-id", G_TYPE_UINT, device.deviceID, "device-index",
G_TYPE_UINT, device.deviceIndex, "pci-slot", G_TYPE_UINT, device.pciSlot,
"serial-number", G_TYPE_UINT64, device.deviceSerialNumber,
"device-identifier", G_TYPE_STRING, device.deviceIdentifier.c_str(),
"num-audio-streams", G_TYPE_UINT, device.numAudioStreams,
"dual-link-support", G_TYPE_BOOLEAN, device.dualLinkSupport,
"sdi-3g-support", G_TYPE_BOOLEAN, device.sdi3GSupport, "sdi-12g-support",
G_TYPE_BOOLEAN, device.sdi12GSupport, "ip-support", G_TYPE_BOOLEAN,
device.ipSupport, "bi-directional-sdi", G_TYPE_BOOLEAN,
device.biDirectionalSDI, "ltc-in-support", G_TYPE_BOOLEAN,
device.ltcInSupport, "ltc-in-on-ref-port", G_TYPE_BOOLEAN,
device.ltcInOnRefPort, "2k-support", G_TYPE_BOOLEAN, device.has2KSupport,
"4k-support", G_TYPE_BOOLEAN, device.has4KSupport, "8k-support",
G_TYPE_BOOLEAN, device.has8KSupport, "multiformat-support",
G_TYPE_BOOLEAN, device.multiFormat, NULL);
if (is_capture) {
gst_structure_set(
properties, "num-vid-inputs", G_TYPE_UINT, device.numVidInputs,
"num-anlg-vid-inputs", G_TYPE_UINT, device.numAnlgVidInputs,
"num-hdmi-vid-inputs", G_TYPE_UINT, device.numHDMIVidInputs,
"num-analog-audio-input-channels", G_TYPE_UINT,
device.numAnalogAudioInputChannels, "num-aes-audio-input-channels",
G_TYPE_UINT, device.numAESAudioInputChannels,
"num-embedded-audio-input-channels", G_TYPE_UINT,
device.numEmbeddedAudioInputChannels, "num-hdmi-audio-input-channels",
G_TYPE_UINT, device.numHDMIAudioInputChannels, NULL);
} else {
gst_structure_set(
properties, "num-vid-outputs", G_TYPE_UINT, device.numVidOutputs,
"num-anlg-vid-outputs", G_TYPE_UINT, device.numAnlgVidOutputs,
"num-hdmi-vid-outputs", G_TYPE_UINT, device.numHDMIVidOutputs,
"num-analog-audio-output-channels", G_TYPE_UINT,
device.numAnalogAudioOutputChannels, "num-aes-audio-output-channels",
G_TYPE_UINT, device.numAESAudioOutputChannels,
"num-embedded-audio-output-channels", G_TYPE_UINT,
device.numEmbeddedAudioOutputChannels, "num-hdmi-audio-output-channels",
G_TYPE_UINT, device.numHDMIAudioOutputChannels, NULL);
}
ret = GST_DEVICE(g_object_new(GST_TYPE_AJA_DEVICE, "display-name",
display_name, "device-class", device_class,
"caps", caps, "properties", properties, NULL));
g_free(display_name);
gst_caps_unref(caps);
gst_structure_free(properties);
GST_AJA_DEVICE(ret)->is_capture = is_capture;
GST_AJA_DEVICE(ret)->device_index = device.deviceIndex;
return ret;
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 Mathieu Duponchelle <mathieu@centricular.com>
* Copyright (C) 2019,2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef _GST_AJA_DEVICE_PROVIDER_H_
#define _GST_AJA_DEVICE_PROVIDER_H_
#include <ajantv2/includes/ntv2devicescanner.h>
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_AJA_DEVICE_PROVIDER gst_aja_device_provider_get_type()
#define GST_AJA_DEVICE_PROVIDER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_DEVICE_PROVIDER, \
GstAjaDeviceProvider))
typedef struct _GstAjaDeviceProvider GstAjaDeviceProvider;
typedef struct _GstAjaDeviceProviderClass GstAjaDeviceProviderClass;
struct _GstAjaDeviceProviderClass {
GstDeviceProviderClass parent_class;
};
struct _GstAjaDeviceProvider {
GstDeviceProvider parent;
};
G_GNUC_INTERNAL
GType gst_aja_device_provider_get_type(void);
#define GST_TYPE_AJA_DEVICE gst_aja_device_get_type()
#define GST_AJA_DEVICE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_DEVICE, GstAjaDevice))
typedef struct _GstAjaDevice GstAjaDevice;
typedef struct _GstAjaDeviceClass GstAjaDeviceClass;
struct _GstAjaDeviceClass {
GstDeviceClass parent_class;
};
struct _GstAjaDevice {
GstDevice parent;
gboolean is_capture;
guint device_index;
};
G_GNUC_INTERNAL
GType gst_aja_device_get_type(void);
G_END_DECLS
#endif /* _GST_AJA_DEVICE_PROVIDER_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/base/base.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstajacommon.h"
G_BEGIN_DECLS
#define GST_TYPE_AJA_SINK (gst_aja_sink_get_type())
#define GST_AJA_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_SINK, GstAjaSink))
#define GST_AJA_SINK_CAST(obj) ((GstAjaSink *)obj)
#define GST_AJA_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AJA_SINK, GstAjaSinkClass))
#define GST_IS_AJA_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AJA_SINK))
#define GST_IS_AJA_SINK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AJA_SINK))
typedef struct _GstAjaSink GstAjaSink;
typedef struct _GstAjaSinkClass GstAjaSinkClass;
struct _GstAjaSink {
GstBaseSink parent;
// Everything below protected by queue lock
GMutex queue_lock;
GCond queue_cond;
GstQueueArray *queue;
gboolean eos;
gboolean playing;
gboolean shutdown;
gboolean draining;
// Hold by set_caps() to wait until drained
GCond drain_cond;
gboolean flushing;
GstAjaNtv2Device *device;
NTV2DeviceID device_id;
GstAllocator *allocator;
// Only allocated on demand
GstBufferPool *buffer_pool;
GstBufferPool *audio_buffer_pool;
GstBufferPool *anc_buffer_pool;
// Properties
gchar *device_identifier;
NTV2Channel channel;
guint queue_size;
guint start_frame, end_frame;
guint output_cpu_core;
GstAjaAudioSystem audio_system_setting;
GstAjaOutputDestination output_destination;
GstAjaSdiMode sdi_mode;
GstAjaTimecodeIndex timecode_index;
gboolean rp188;
GstAjaReferenceSource reference_source;
gint cea608_line_number;
gint cea708_line_number;
NTV2AudioSystem audio_system;
NTV2VideoFormat video_format;
bool quad_mode;
NTV2VANCMode vanc_mode;
guint32 f2_start_line;
NTV2TCIndexes *tc_indexes;
GstCaps *configured_caps;
GstVideoInfo configured_info;
gint configured_audio_channels;
AJAThread *output_thread;
};
struct _GstAjaSinkClass {
GstBaseSinkClass parent_class;
};
G_GNUC_INTERNAL
GType gst_aja_sink_get_type(void);
G_END_DECLS

View file

@ -0,0 +1,294 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstajacommon.h"
#include "gstajasinkcombiner.h"
GST_DEBUG_CATEGORY_STATIC(gst_aja_sink_combiner_debug);
#define GST_CAT_DEFAULT gst_aja_sink_combiner_debug
static GstStaticPadTemplate video_sink_template = GST_STATIC_PAD_TEMPLATE(
"video", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("video/x-raw"));
static GstStaticPadTemplate audio_sink_template =
GST_STATIC_PAD_TEMPLATE("audio", GST_PAD_SINK, GST_PAD_REQUEST,
GST_STATIC_CAPS("audio/x-raw, "
"format = (string) S32LE, "
"rate = (int) 48000, "
"channels = (int) [ 1, 16 ], "
"layout = (string) interleaved"));
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
"src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("video/x-raw"));
G_DEFINE_TYPE(GstAjaSinkCombiner, gst_aja_sink_combiner, GST_TYPE_AGGREGATOR);
#define parent_class gst_aja_sink_combiner_parent_class
static void gst_aja_sink_combiner_finalize(GObject *object) {
GstAjaSinkCombiner *self = GST_AJA_SINK_COMBINER(object);
GST_OBJECT_LOCK(self);
gst_caps_replace(&self->audio_caps, NULL);
gst_caps_replace(&self->video_caps, NULL);
GST_OBJECT_UNLOCK(self);
G_OBJECT_CLASS(parent_class)->finalize(object);
}
static GstFlowReturn gst_aja_sink_combiner_aggregate(GstAggregator *aggregator,
gboolean timeout) {
GstAjaSinkCombiner *self = GST_AJA_SINK_COMBINER(aggregator);
GstBuffer *video_buffer, *audio_buffer;
if (gst_aggregator_pad_is_eos(GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad)) &&
gst_aggregator_pad_is_eos(GST_AGGREGATOR_PAD_CAST(self->video_sinkpad))) {
GST_DEBUG_OBJECT(self, "All pads EOS");
return GST_FLOW_EOS;
}
// FIXME: We currently assume that upstream provides
// - properly chunked buffers (1 buffer = 1 video frame)
// - properly synchronized buffers (audio/video starting at the same time)
// - no gaps
//
// This can be achieved externally with elements like audiobuffersplit and
// videorate.
video_buffer = gst_aggregator_pad_peek_buffer(
GST_AGGREGATOR_PAD_CAST(self->video_sinkpad));
if (!video_buffer) return GST_AGGREGATOR_FLOW_NEED_DATA;
audio_buffer = gst_aggregator_pad_peek_buffer(
GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad));
if (!audio_buffer && !gst_aggregator_pad_is_eos(
GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad))) {
gst_buffer_unref(video_buffer);
GST_TRACE_OBJECT(self, "Audio not ready yet, waiting");
return GST_AGGREGATOR_FLOW_NEED_DATA;
}
gst_aggregator_pad_drop_buffer(GST_AGGREGATOR_PAD_CAST(self->video_sinkpad));
video_buffer = gst_buffer_make_writable(video_buffer);
GST_TRACE_OBJECT(self,
"Outputting buffer with video %" GST_PTR_FORMAT
" and audio %" GST_PTR_FORMAT,
video_buffer, audio_buffer);
if (audio_buffer) {
gst_buffer_add_aja_audio_meta(video_buffer, audio_buffer);
gst_buffer_unref(audio_buffer);
gst_aggregator_pad_drop_buffer(
GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad));
}
if (!gst_pad_has_current_caps(GST_AGGREGATOR_SRC_PAD(self)) ||
self->caps_changed) {
GstCaps *caps = gst_caps_copy(self->video_caps);
GstStructure *s;
s = gst_caps_get_structure(caps, 0);
if (self->audio_caps) {
const GstStructure *s2;
gint audio_channels;
s2 = gst_caps_get_structure(self->audio_caps, 0);
gst_structure_get_int(s2, "channels", &audio_channels);
gst_structure_set(s, "audio-channels", G_TYPE_INT, audio_channels, NULL);
} else {
gst_structure_set(s, "audio-channels", G_TYPE_INT, 0, NULL);
}
GST_DEBUG_OBJECT(self, "Configuring caps %" GST_PTR_FORMAT, caps);
gst_aggregator_set_src_caps(GST_AGGREGATOR(self), caps);
gst_caps_unref(caps);
self->caps_changed = FALSE;
}
// Update the position for synchronization purposes
GST_AGGREGATOR_PAD_CAST(GST_AGGREGATOR_SRC_PAD(self))->segment.position =
GST_BUFFER_PTS(video_buffer);
if (GST_BUFFER_DURATION_IS_VALID(video_buffer))
GST_AGGREGATOR_PAD_CAST(GST_AGGREGATOR_SRC_PAD(self))->segment.position +=
GST_BUFFER_DURATION(video_buffer);
return gst_aggregator_finish_buffer(GST_AGGREGATOR_CAST(self), video_buffer);
}
static gboolean gst_aja_sink_combiner_sink_event(GstAggregator *aggregator,
GstAggregatorPad *agg_pad,
GstEvent *event) {
GstAjaSinkCombiner *self = GST_AJA_SINK_COMBINER(aggregator);
switch (GST_EVENT_TYPE(event)) {
case GST_EVENT_SEGMENT: {
const GstSegment *segment;
gst_event_parse_segment(event, &segment);
gst_aggregator_update_segment(GST_AGGREGATOR(self), segment);
break;
}
case GST_EVENT_CAPS: {
GstCaps *caps;
gst_event_parse_caps(event, &caps);
if (agg_pad == GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad)) {
GST_OBJECT_LOCK(self);
gst_caps_replace(&self->audio_caps, caps);
self->caps_changed = TRUE;
GST_OBJECT_UNLOCK(self);
} else if (agg_pad == GST_AGGREGATOR_PAD_CAST(self->video_sinkpad)) {
GST_OBJECT_LOCK(self);
gst_caps_replace(&self->video_caps, caps);
self->caps_changed = TRUE;
GST_OBJECT_UNLOCK(self);
}
break;
}
default:
break;
}
return GST_AGGREGATOR_CLASS(parent_class)
->sink_event(aggregator, agg_pad, event);
}
static gboolean gst_aja_sink_combiner_sink_query(GstAggregator *aggregator,
GstAggregatorPad *agg_pad,
GstQuery *query) {
GstAjaSinkCombiner *self = GST_AJA_SINK_COMBINER(aggregator);
switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_CAPS: {
GstCaps *filter, *caps;
gst_query_parse_caps(query, &filter);
if (agg_pad == GST_AGGREGATOR_PAD_CAST(self->audio_sinkpad)) {
caps = gst_pad_get_pad_template_caps(GST_PAD(agg_pad));
} else if (agg_pad == GST_AGGREGATOR_PAD_CAST(self->video_sinkpad)) {
caps = gst_pad_peer_query_caps(GST_AGGREGATOR_SRC_PAD(self), NULL);
caps = gst_caps_make_writable(caps);
guint caps_size = gst_caps_get_size(caps);
for (guint i = 0; i < caps_size; i++) {
GstStructure *s = gst_caps_get_structure(caps, i);
gst_structure_remove_field(s, "audio-channels");
}
} else {
g_assert_not_reached();
}
if (filter) {
GstCaps *tmp = gst_caps_intersect(filter, caps);
gst_caps_unref(caps);
caps = tmp;
}
gst_query_set_caps_result(query, caps);
return TRUE;
}
case GST_QUERY_ALLOCATION: {
// Proxy to the sink for both pads so that the AJA allocator can be
// used upstream as needed.
return gst_pad_peer_query(GST_AGGREGATOR_SRC_PAD(self), query);
}
default:
break;
}
return GST_AGGREGATOR_CLASS(parent_class)
->sink_query(aggregator, agg_pad, query);
}
static gboolean gst_aja_sink_combiner_negotiate(GstAggregator *aggregator) {
return TRUE;
}
static gboolean gst_aja_sink_combiner_stop(GstAggregator *aggregator) {
GstAjaSinkCombiner *self = GST_AJA_SINK_COMBINER(aggregator);
GST_OBJECT_LOCK(self);
gst_caps_replace(&self->audio_caps, NULL);
gst_caps_replace(&self->video_caps, NULL);
GST_OBJECT_UNLOCK(self);
return TRUE;
}
static void gst_aja_sink_combiner_class_init(GstAjaSinkCombinerClass *klass) {
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstAggregatorClass *aggregator_class;
gobject_class = (GObjectClass *)klass;
gstelement_class = (GstElementClass *)klass;
aggregator_class = (GstAggregatorClass *)klass;
gobject_class->finalize = gst_aja_sink_combiner_finalize;
gst_element_class_set_static_metadata(
gstelement_class, "AJA sink audio/video combiner", "Audio/Video/Combiner",
"Combines corresponding audio/video frames",
"Sebastian Dröge <sebastian@centricular.com>");
gst_element_class_add_static_pad_template_with_gtype(
gstelement_class, &video_sink_template, GST_TYPE_AGGREGATOR_PAD);
gst_element_class_add_static_pad_template_with_gtype(
gstelement_class, &audio_sink_template, GST_TYPE_AGGREGATOR_PAD);
gst_element_class_add_static_pad_template_with_gtype(
gstelement_class, &src_template, GST_TYPE_AGGREGATOR_PAD);
aggregator_class->aggregate = gst_aja_sink_combiner_aggregate;
aggregator_class->stop = gst_aja_sink_combiner_stop;
aggregator_class->sink_event = gst_aja_sink_combiner_sink_event;
aggregator_class->sink_query = gst_aja_sink_combiner_sink_query;
aggregator_class->negotiate = gst_aja_sink_combiner_negotiate;
aggregator_class->get_next_time = gst_aggregator_simple_get_next_time;
// We don't support requesting new pads
gstelement_class->request_new_pad = NULL;
GST_DEBUG_CATEGORY_INIT(gst_aja_sink_combiner_debug, "ajasinkcombiner", 0,
"AJA sink combiner");
}
static void gst_aja_sink_combiner_init(GstAjaSinkCombiner *self) {
GstPadTemplate *templ;
templ = gst_static_pad_template_get(&video_sink_template);
self->video_sinkpad =
GST_PAD(g_object_new(GST_TYPE_AGGREGATOR_PAD, "name", "video",
"direction", GST_PAD_SINK, "template", templ, NULL));
gst_object_unref(templ);
gst_element_add_pad(GST_ELEMENT_CAST(self), self->video_sinkpad);
templ = gst_static_pad_template_get(&audio_sink_template);
self->audio_sinkpad =
GST_PAD(g_object_new(GST_TYPE_AGGREGATOR_PAD, "name", "audio",
"direction", GST_PAD_SINK, "template", templ, NULL));
gst_object_unref(templ);
gst_element_add_pad(GST_ELEMENT_CAST(self), self->audio_sinkpad);
}

View file

@ -0,0 +1,60 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/base/base.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstajacommon.h"
G_BEGIN_DECLS
#define GST_TYPE_AJA_SINK_COMBINER (gst_aja_sink_combiner_get_type())
#define GST_AJA_SINK_COMBINER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_SINK_COMBINER, \
GstAjaSinkCombiner))
#define GST_AJA_SINK_COMBINER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AJA_SINK_COMBINER, \
GstAjaSinkCombinerClass))
#define IS_GST_AJA_SINK_COMBINER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AJA_SINK_COMBINER))
#define IS_GST_AJA_SINK_COMBINER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AJA_SINK_COMBINER))
typedef struct _GstAjaSinkCombiner GstAjaSinkCombiner;
typedef struct _GstAjaSinkCombinerClass GstAjaSinkCombinerClass;
struct _GstAjaSinkCombiner {
GstAggregator parent;
GstPad *audio_sinkpad, *video_sinkpad;
GstCaps *audio_caps, *video_caps;
gboolean caps_changed;
};
struct _GstAjaSinkCombinerClass {
GstAggregatorClass parent_class;
};
G_GNUC_INTERNAL
GType gst_aja_sink_combiner_get_type(void);
G_END_DECLS

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,102 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/base/base.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstajacommon.h"
G_BEGIN_DECLS
#define GST_TYPE_AJA_SRC (gst_aja_src_get_type())
#define GST_AJA_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_SRC, GstAjaSrc))
#define GST_AJA_SRC_CAST(obj) ((GstAjaSrc *)obj)
#define GST_AJA_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AJA_SRC, GstAjaSrcClass))
#define GST_IS_AJA_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AJA_SRC))
#define GST_IS_AJA_SRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AJA_SRC))
typedef struct _GstAjaSrc GstAjaSrc;
typedef struct _GstAjaSrcClass GstAjaSrcClass;
struct _GstAjaSrc {
GstPushSrc parent;
// Everything below protected by queue lock
GMutex queue_lock;
GCond queue_cond;
GstQueueArray *queue;
guint queue_num_frames;
gboolean playing;
gboolean shutdown;
gboolean flushing;
GstAjaNtv2Device *device;
NTV2DeviceID device_id;
GstAllocator *allocator;
GstBufferPool *buffer_pool;
GstBufferPool *audio_buffer_pool;
GstBufferPool *anc_buffer_pool;
// Properties
gchar *device_identifier;
NTV2Channel channel;
GstAjaAudioSystem audio_system_setting;
GstAjaVideoFormat video_format_setting;
GstAjaSdiMode sdi_mode;
GstAjaInputSource input_source;
GstAjaAudioSource audio_source;
GstAjaEmbeddedAudioInput embedded_audio_input;
GstAjaTimecodeIndex timecode_index;
gboolean rp188;
GstAjaReferenceSource reference_source;
GstAjaClosedCaptionCaptureMode closed_caption_capture_mode;
guint queue_size;
guint start_frame, end_frame;
guint capture_cpu_core;
gboolean signal;
NTV2AudioSystem audio_system;
NTV2VideoFormat video_format;
bool quad_mode;
NTV2VANCMode vanc_mode;
NTV2InputSource configured_input_source;
GstVideoInfo configured_info; // Based on properties
GstVideoInfo current_info; // Based on properties + stream metadata
gint configured_audio_channels;
AJAThread *capture_thread;
};
struct _GstAjaSrcClass {
GstPushSrcClass parent_class;
};
G_GNUC_INTERNAL
GType gst_aja_src_get_type(void);
G_END_DECLS

View file

@ -0,0 +1,292 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/audio/audio.h>
#include "gstajacommon.h"
#include "gstajasrcdemux.h"
GST_DEBUG_CATEGORY_STATIC(gst_aja_src_demux_debug);
#define GST_CAT_DEFAULT gst_aja_src_demux_debug
static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE(
"video", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("video/x-raw"));
static GstStaticPadTemplate audio_src_template = GST_STATIC_PAD_TEMPLATE(
"audio", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-raw"));
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE(
"sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("video/x-raw"));
static GstFlowReturn gst_aja_src_demux_sink_chain(GstPad *pad,
GstObject *parent,
GstBuffer *buffer);
static gboolean gst_aja_src_demux_sink_event(GstPad *pad, GstObject *parent,
GstEvent *event);
static gboolean gst_aja_src_demux_audio_src_query(GstPad *pad,
GstObject *parent,
GstQuery *query);
static gboolean gst_aja_src_demux_video_src_query(GstPad *pad,
GstObject *parent,
GstQuery *query);
#define parent_class gst_aja_src_demux_parent_class
G_DEFINE_TYPE(GstAjaSrcDemux, gst_aja_src_demux, GST_TYPE_ELEMENT);
static void gst_aja_src_demux_class_init(GstAjaSrcDemuxClass *klass) {
GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
gst_element_class_add_static_pad_template(element_class, &sink_template);
gst_element_class_add_static_pad_template(element_class, &video_src_template);
gst_element_class_add_static_pad_template(element_class, &audio_src_template);
gst_element_class_set_static_metadata(
element_class, "AJA audio/video source demuxer", "Audio/Video/Demux",
"Demuxes audio/video from video buffers",
"Sebastian Dröge <sebastian@centricular.com>");
GST_DEBUG_CATEGORY_INIT(gst_aja_src_demux_debug, "ajasrcdemux", 0,
"AJA source demuxer");
}
static void gst_aja_src_demux_init(GstAjaSrcDemux *self) {
self->sink = gst_pad_new_from_static_template(&sink_template, "sink");
gst_pad_set_chain_function(self->sink,
GST_DEBUG_FUNCPTR(gst_aja_src_demux_sink_chain));
gst_pad_set_event_function(self->sink,
GST_DEBUG_FUNCPTR(gst_aja_src_demux_sink_event));
gst_element_add_pad(GST_ELEMENT(self), self->sink);
self->audio_src =
gst_pad_new_from_static_template(&audio_src_template, "audio");
gst_pad_set_query_function(
self->audio_src, GST_DEBUG_FUNCPTR(gst_aja_src_demux_audio_src_query));
gst_element_add_pad(GST_ELEMENT(self), self->audio_src);
self->video_src =
gst_pad_new_from_static_template(&video_src_template, "video");
gst_pad_set_query_function(
self->video_src, GST_DEBUG_FUNCPTR(gst_aja_src_demux_video_src_query));
gst_element_add_pad(GST_ELEMENT(self), self->video_src);
}
static GstFlowReturn gst_aja_src_demux_sink_chain(GstPad *pad,
GstObject *parent,
GstBuffer *buffer) {
GstAjaSrcDemux *self = GST_AJA_SRC_DEMUX(parent);
GstAjaAudioMeta *meta = gst_buffer_get_aja_audio_meta(buffer);
GstFlowReturn audio_flow_ret = GST_FLOW_OK;
GstFlowReturn video_flow_ret = GST_FLOW_OK;
if (meta) {
GstBuffer *audio_buffer;
buffer = gst_buffer_make_writable(buffer);
meta = gst_buffer_get_aja_audio_meta(buffer);
audio_buffer = gst_buffer_ref(meta->buffer);
gst_buffer_remove_meta(buffer, GST_META_CAST(meta));
audio_flow_ret = gst_pad_push(self->audio_src, audio_buffer);
} else {
GstEvent *event =
gst_event_new_gap(GST_BUFFER_PTS(buffer), GST_BUFFER_DURATION(buffer));
gst_pad_push_event(self->audio_src, event);
}
video_flow_ret = gst_pad_push(self->video_src, buffer);
// Combine flows the way it makes sense
if (video_flow_ret == GST_FLOW_NOT_LINKED &&
audio_flow_ret == GST_FLOW_NOT_LINKED)
return GST_FLOW_NOT_LINKED;
if (video_flow_ret == GST_FLOW_EOS && audio_flow_ret == GST_FLOW_EOS)
return GST_FLOW_EOS;
if (video_flow_ret == GST_FLOW_FLUSHING ||
video_flow_ret <= GST_FLOW_NOT_NEGOTIATED)
return video_flow_ret;
if (audio_flow_ret == GST_FLOW_FLUSHING ||
audio_flow_ret <= GST_FLOW_NOT_NEGOTIATED)
return audio_flow_ret;
return GST_FLOW_OK;
}
static gboolean gst_aja_src_demux_sink_event(GstPad *pad, GstObject *parent,
GstEvent *event) {
GstAjaSrcDemux *self = GST_AJA_SRC_DEMUX(parent);
switch (GST_EVENT_TYPE(event)) {
case GST_EVENT_CAPS: {
GstCaps *caps;
GstStructure *s;
GstAudioInfo audio_info;
gint audio_channels = 0;
gst_event_parse_caps(event, &caps);
s = gst_caps_get_structure(caps, 0);
gst_structure_get_int(s, "audio-channels", &audio_channels);
GstCaps *audio_caps, *video_caps;
gst_audio_info_init(&audio_info);
gst_audio_info_set_format(&audio_info, GST_AUDIO_FORMAT_S32LE, 48000,
audio_channels ? audio_channels : 1, NULL);
audio_caps = gst_audio_info_to_caps(&audio_info);
gst_pad_set_caps(self->audio_src, audio_caps);
gst_caps_unref(audio_caps);
video_caps = gst_caps_ref(caps);
gst_event_unref(event);
video_caps = gst_caps_make_writable(video_caps);
s = gst_caps_get_structure(video_caps, 0);
gst_structure_remove_field(s, "audio-channels");
gst_pad_set_caps(self->video_src, video_caps);
gst_caps_unref(video_caps);
return TRUE;
}
default:
return gst_pad_event_default(pad, parent, event);
}
}
static gboolean gst_aja_src_demux_audio_src_query(GstPad *pad,
GstObject *parent,
GstQuery *query) {
GstAjaSrcDemux *self = GST_AJA_SRC_DEMUX(parent);
switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_CAPS: {
GstCaps *filter, *caps;
gst_query_parse_caps(query, &filter);
if ((caps = gst_pad_get_current_caps(pad))) {
GST_DEBUG_OBJECT(
pad, "Returning currently negotiated caps %" GST_PTR_FORMAT, caps);
} else if ((caps = gst_pad_peer_query_caps(self->sink, NULL))) {
guint n;
GstAudioInfo audio_info;
gint audio_channels = 0;
GstCaps *tmp;
GST_DEBUG_OBJECT(pad, "Got upstream caps %" GST_PTR_FORMAT, caps);
n = gst_caps_get_size(caps);
for (guint i = 0; i < n; i++) {
GstStructure *s = gst_caps_get_structure(caps, i);
gint tmp;
if (!gst_structure_get_int(s, "audio-channels", &tmp)) {
tmp = 0;
}
// No audio channels in all caps
if (tmp == 0 || (audio_channels != 0 && audio_channels != tmp)) {
audio_channels = 0;
break;
}
audio_channels = tmp;
}
gst_audio_info_init(&audio_info);
gst_audio_info_set_format(&audio_info, GST_AUDIO_FORMAT_S32LE, 48000,
audio_channels ? audio_channels : 1, NULL);
tmp = gst_audio_info_to_caps(&audio_info);
gst_caps_unref(caps);
caps = tmp;
if (!audio_channels) {
gst_caps_set_simple(caps, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
NULL);
}
GST_DEBUG_OBJECT(pad, "Returning caps %" GST_PTR_FORMAT, caps);
} else {
caps = gst_pad_get_pad_template_caps(pad);
GST_DEBUG_OBJECT(pad, "Returning template caps %" GST_PTR_FORMAT, caps);
}
if (filter) {
GstCaps *tmp =
gst_caps_intersect_full(filter, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref(caps);
caps = tmp;
}
gst_query_set_caps_result(query, caps);
gst_caps_unref(caps);
return TRUE;
}
default:
return gst_pad_query_default(pad, parent, query);
}
}
static gboolean gst_aja_src_demux_video_src_query(GstPad *pad,
GstObject *parent,
GstQuery *query) {
GstAjaSrcDemux *self = GST_AJA_SRC_DEMUX(parent);
switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_CAPS: {
GstCaps *filter, *caps;
gst_query_parse_caps(query, &filter);
if ((caps = gst_pad_get_current_caps(pad))) {
GST_DEBUG_OBJECT(
pad, "Returning currently negotiated caps %" GST_PTR_FORMAT, caps);
} else if ((caps = gst_pad_peer_query_caps(self->sink, NULL))) {
guint n;
GST_DEBUG_OBJECT(pad, "Returning upstream caps %" GST_PTR_FORMAT, caps);
caps = gst_caps_make_writable(caps);
n = gst_caps_get_size(caps);
for (guint i = 0; i < n; i++) {
GstStructure *s = gst_caps_get_structure(caps, i);
gst_structure_remove_field(s, "audio-channels");
}
} else {
caps = gst_pad_get_pad_template_caps(pad);
GST_DEBUG_OBJECT(pad, "Returning template caps %" GST_PTR_FORMAT, caps);
}
if (filter) {
GstCaps *tmp =
gst_caps_intersect_full(filter, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref(caps);
caps = tmp;
}
gst_query_set_caps_result(query, caps);
gst_caps_unref(caps);
return TRUE;
}
default:
return gst_pad_query_default(pad, parent, query);
}
}

View file

@ -0,0 +1,59 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/base/base.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstajacommon.h"
G_BEGIN_DECLS
#define GST_TYPE_AJA_SRC_DEMUX (gst_aja_src_demux_get_type())
#define GST_AJA_SRC_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_SRC_DEMUX, GstAjaSrcDemux))
#define GST_AJA_SRC_DEMUX_CAST(obj) ((GstAjaSrcDemux *)obj)
#define GST_AJA_SRC_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AJA_SRC_DEMUX, \
GstAjaSrcDemuxClass))
#define GST_IS_AJA_SRC_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AJA_SRC_DEMUX))
#define GST_IS_AJA_SRC_DEMUX_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AJA_SRC_DEMUX))
typedef struct _GstAjaSrcDemux GstAjaSrcDemux;
typedef struct _GstAjaSrcDemuxClass GstAjaSrcDemuxClass;
struct _GstAjaSrcDemux {
GstElement parent;
GstPad *sink;
GstPad *video_src, *audio_src;
};
struct _GstAjaSrcDemuxClass {
GstElementClass parent_class;
};
G_GNUC_INTERNAL
GType gst_aja_src_demux_get_type(void);
G_END_DECLS

View file

@ -0,0 +1,112 @@
project('gst-aja', 'cpp',
version : '0.1.0',
meson_version : '>= 0.63.0',
default_options : [ 'warning_level=1',
'buildtype=debugoptimized',
'cpp_std=c++11',
'cpp_eh=none',
'cpp_rtti=false',
]
)
plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir'))
cxx = meson.get_compiler('cpp')
if cxx.has_argument('-fvisibility=hidden')
add_project_arguments('-fvisibility=hidden', language: 'cpp')
endif
if cxx.get_id() == 'msvc'
# Ignore several spurious warnings for things gstreamer does very commonly
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
# NOTE: Only add warnings here if you are sure they're spurious
test_cppflags = []
msvc_args = [
'/wd4018', # implicit signed/unsigned conversion
'/wd4146', # unary minus on unsigned (beware INT_MIN)
'/wd4244', # lossy type conversion (e.g. double -> int)
'/wd4305', # truncating type conversion (e.g. double -> float)
]
add_project_arguments(msvc_args, language : 'cpp')
# Disable SAFESEH with MSVC for plugins and libs that use external deps that
# are built with MinGW
noseh_link_args = ['/SAFESEH:NO']
else
test_cppflags = ['-Wno-non-virtual-dtor']
noseh_link_args = []
endif
common_flags = [
'-DAJALinux=1',
'-DAJA_LINUX=1',
]
foreach cxxflag: test_cppflags
if cxx.has_argument(cxxflag)
common_flags += [ cxxflag ]
endif
endforeach
gst_dep = dependency('gstreamer-1.0', version : '>= 1.18', required : true)
gstbase_dep = dependency('gstreamer-base-1.0', version : '>= 1.18', required : true)
gstaudio_dep = dependency('gstreamer-audio-1.0', version : '>= 1.18', required : true)
gstvideo_dep = dependency('gstreamer-video-1.0', version : '>= 1.18', required : true)
thread_dep = dependency('threads')
rt_dep = cxx.find_library('rt', required : false)
aja_sdk_dir = get_option('aja-sdk-dir')
if aja_sdk_dir == ''
ajantv2_dep = dependency('libajantv2')
aja_includedirs = []
if not ajantv2_dep.found()
subdir_done()
endif
else
aja_includedirs = include_directories(
f'@aja_sdk_dir@/ajalibraries',
f'@aja_sdk_dir@/ajalibraries/ajantv2/includes',
f'@aja_sdk_dir@/ajalibraries/ajantv2/src/lin',
)
message('Looking for AJA SDK in directory ' + aja_sdk_dir)
if not cxx.has_header('ajabase/common/videotypes.h',
include_directories : aja_includedirs,
)
error('Cannot find AJA SDK')
endif
ajantv2_lib = cxx.find_library('ajantv2',
# If the header is found, this should also be
required : true,
dirs : [f'@aja_sdk_dir@/lib'],
)
ajantv2_dep = declare_dependency(
dependencies: ajantv2_lib,
include_directories: aja_includedirs,
)
endif
gstaja = library('gstaja',
['plugin.cpp',
'gstajacommon.cpp',
'gstajasink.cpp',
'gstajasinkcombiner.cpp',
'gstajasrc.cpp',
'gstajasrcdemux.cpp',
'gstajadeviceprovider.cpp',
],
cpp_args : [
'-DPACKAGE="gst-aja"',
'-DGST_PACKAGE_NAME="gstreamer-aja"',
'-DGST_PACKAGE_ORIGIN="https://github.com/centricular/gstreamer-aja"',
'-DVERSION="@0@"'.format(meson.project_version())] + common_flags,
link_args : noseh_link_args,
dependencies : [gstvideo_dep, gstaudio_dep, gstbase_dep, gst_dep, ajantv2_dep, thread_dep, rt_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -0,0 +1,2 @@
option('aja-sdk-dir', type : 'string', value : '',
description : 'Directory with AJA SDK, e.g. ntv2sdklinux_16.0.0.4')

View file

@ -0,0 +1,53 @@
/* GStreamer
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ajabase/system/debug.h>
#include <gst/gst.h>
#include "gstajacommon.h"
#include "gstajadeviceprovider.h"
#include "gstajasink.h"
#include "gstajasinkcombiner.h"
#include "gstajasrc.h"
#include "gstajasrcdemux.h"
static gboolean plugin_init(GstPlugin* plugin) {
AJADebug::Open();
gst_aja_common_init();
gst_element_register(plugin, "ajasrc", GST_RANK_NONE, GST_TYPE_AJA_SRC);
gst_element_register(plugin, "ajasrcdemux", GST_RANK_NONE,
GST_TYPE_AJA_SRC_DEMUX);
gst_element_register(plugin, "ajasink", GST_RANK_NONE, GST_TYPE_AJA_SINK);
gst_element_register(plugin, "ajasinkcombiner", GST_RANK_NONE,
GST_TYPE_AJA_SINK_COMBINER);
gst_device_provider_register(plugin, "ajadeviceprovider", GST_RANK_PRIMARY,
GST_TYPE_AJA_DEVICE_PROVIDER);
return TRUE;
}
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, aja,
"GStreamer AJA plugin", plugin_init, VERSION, "LGPL",
PACKAGE_NAME, GST_PACKAGE_ORIGIN)

9
subprojects/ntv2.wrap Normal file
View file

@ -0,0 +1,9 @@
[wrap-file]
directory = ntv2-16.2-bugfix5
source_url = https://github.com/aja-video/ntv2/archive/refs/tags/v16.2-bugfix5.tar.gz
source_filename = ntv2-16.2-bugfix5.tar.gz
source_hash = 560c798c3a43aa0cef1cba6be5adb669ec72e648c28814158eb649275efc9f88
diff_files = ntv2-16.2-bugfix5/ntv2-16.2-bugfix5.meson.patch
[provide]
libajantv2 = libajantv2_dep

View file

@ -0,0 +1,167 @@
--- /dev/null 2023-10-13 08:29:31.027000134 +0300
+++ ntv2-16.2-bugfix5/meson.build 2023-10-21 09:58:37.680821179 +0300
@@ -0,0 +1,164 @@
+project('ntv2', 'cpp',
+ version : '16.2-bugfix5',
+ meson_version : '>= 0.54.0',
+ default_options : [ 'warning_level=1',
+ 'buildtype=debugoptimized',
+ 'cpp_std=c++11',
+ 'cpp_eh=none',
+ 'cpp_rtti=false',
+ ]
+)
+
+cxx = meson.get_compiler('cpp')
+test_cppflags = ['-Wno-non-virtual-dtor']
+
+common_flags = [
+ '-DAJALinux=1',
+ '-DAJA_LINUX=1',
+]
+foreach cxxflag: test_cppflags
+ if cxx.has_argument(cxxflag)
+ common_flags += [ cxxflag ]
+ endif
+endforeach
+
+thread_dep = dependency('threads')
+rt_dep = cxx.find_library('rt', required : false)
+
+ajantv2_sources = [
+ 'ajalibraries/ajaanc/src/ancillarydata.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydatafactory.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_cea608.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_cea608_line21.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_cea608_vanc.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_cea708.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_framestatusinfo524D.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_framestatusinfo5251.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_hdr_hdr10.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_hdr_hlg.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_hdr_sdr.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_timecode.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_timecode_atc.cpp',
+ 'ajalibraries/ajaanc/src/ancillarydata_timecode_vitc.cpp',
+ 'ajalibraries/ajaanc/src/ancillarylist.cpp',
+ 'ajalibraries/ajabase/system/atomic.cpp',
+ 'ajalibraries/ajabase/common/audioutilities.cpp',
+ 'ajalibraries/ajabase/common/buffer.cpp',
+ 'ajalibraries/ajabase/common/common.cpp',
+ 'ajalibraries/ajabase/system/debug.cpp',
+ 'ajalibraries/ajabase/common/dpx_hdr.cpp',
+ 'ajalibraries/ajabase/common/dpxfileio.cpp',
+ 'ajalibraries/ajabase/system/event.cpp',
+ 'ajalibraries/ajabase/system/linux/eventimpl.cpp',
+ 'ajalibraries/ajabase/system/file_io.cpp',
+ 'ajalibraries/ajabase/common/guid.cpp',
+ 'ajalibraries/ajabase/system/info.cpp',
+ 'ajalibraries/ajabase/system/linux/infoimpl.cpp',
+ 'ajalibraries/ajabase/network/ip_socket.cpp',
+ 'ajalibraries/ajabase/system/lock.cpp',
+ 'ajalibraries/ajabase/system/linux/lockimpl.cpp',
+ 'ajalibraries/ajabase/system/memory.cpp',
+ 'ajalibraries/ajabase/common/options_popt.cpp',
+ 'ajalibraries/ajabase/common/performance.cpp',
+ 'ajalibraries/ajabase/common/pixelformat.cpp',
+ 'ajalibraries/ajabase/pnp/pnp.cpp',
+ 'ajalibraries/ajabase/pnp/linux/pnpimpl.cpp',
+ 'ajalibraries/ajabase/system/process.cpp',
+ 'ajalibraries/ajabase/system/linux/processimpl.cpp',
+ 'ajalibraries/ajabase/system/system.cpp',
+ 'ajalibraries/ajabase/system/systemtime.cpp',
+ 'ajalibraries/ajabase/common/testpatterngen.cpp',
+ 'ajalibraries/ajabase/system/thread.cpp',
+ 'ajalibraries/ajabase/system/linux/threadimpl.cpp',
+ 'ajalibraries/ajabase/common/timebase.cpp',
+ 'ajalibraries/ajabase/common/timecode.cpp',
+ 'ajalibraries/ajabase/common/timecodeburn.cpp',
+ 'ajalibraries/ajabase/common/timer.cpp',
+ 'ajalibraries/ajabase/network/udp_socket.cpp',
+ 'ajalibraries/ajabase/common/videoutilities.cpp',
+ 'ajalibraries/ajabase/common/wavewriter.cpp',
+ 'ajalibraries/ajabase/persistence/persistence.cpp',
+ 'ajalibraries/ajantv2/src/ntv2audio.cpp',
+ 'ajalibraries/ajantv2/src/ntv2anc.cpp',
+ 'ajalibraries/ajantv2/src/ntv2autocirculate.cpp',
+ 'ajalibraries/ajantv2/src/ntv2bitfile.cpp',
+ 'ajalibraries/ajantv2/src/ntv2bitfilemanager.cpp',
+ 'ajalibraries/ajantv2/src/ntv2card.cpp',
+ 'ajalibraries/ajantv2/src/ntv2config2022.cpp',
+ 'ajalibraries/ajantv2/src/ntv2config2110.cpp',
+ 'ajalibraries/ajantv2/src/ntv2configts2022.cpp',
+ 'ajalibraries/ajantv2/src/ntv2csclut.cpp',
+ 'ajalibraries/ajantv2/src/ntv2cscmatrix.cpp',
+ 'ajalibraries/ajantv2/src/ntv2debug.cpp',
+ 'ajalibraries/ajantv2/src/ntv2devicefeatures.cpp',
+ 'ajalibraries/ajantv2/src/ntv2devicescanner.cpp',
+ 'ajalibraries/ajantv2/src/ntv2discover.cpp',
+ 'ajalibraries/ajantv2/src/ntv2dma.cpp',
+ 'ajalibraries/ajantv2/src/ntv2dynamicdevice.cpp',
+ 'ajalibraries/ajantv2/src/ntv2hdmi.cpp',
+ 'ajalibraries/ajantv2/src/ntv2hevc.cpp',
+ 'ajalibraries/ajantv2/src/ntv2driverinterface.cpp',
+ 'ajalibraries/ajantv2/src/ntv2enhancedcsc.cpp',
+ 'ajalibraries/ajantv2/src/ntv2formatdescriptor.cpp',
+ 'ajalibraries/ajantv2/src/ntv2interrupts.cpp',
+ 'ajalibraries/ajantv2/src/ntv2konaflashprogram.cpp',
+ 'ajalibraries/ajantv2/src/lin/ntv2linuxdriverinterface.cpp',
+ 'ajalibraries/ajantv2/src/ntv2mailbox.cpp',
+ 'ajalibraries/ajantv2/src/ntv2mbcontroller.cpp',
+ 'ajalibraries/ajantv2/src/ntv2mcsfile.cpp',
+ 'ajalibraries/ajantv2/src/ntv2nubaccess.cpp',
+ 'ajalibraries/ajantv2/src/ntv2nubpktcom.cpp',
+ 'ajalibraries/ajantv2/src/ntv2publicinterface.cpp',
+ 'ajalibraries/ajantv2/src/ntv2register.cpp',
+ 'ajalibraries/ajantv2/src/ntv2registerexpert.cpp',
+ 'ajalibraries/ajantv2/src/ntv2resample.cpp',
+ 'ajalibraries/ajantv2/src/ntv2routingexpert.cpp',
+ 'ajalibraries/ajantv2/src/ntv2rp188.cpp',
+ 'ajalibraries/ajantv2/src/ntv2serialcontrol.cpp',
+ 'ajalibraries/ajantv2/src/ntv2signalrouter.cpp',
+ 'ajalibraries/ajantv2/src/ntv2spiinterface.cpp',
+ 'ajalibraries/ajantv2/src/ntv2subscriptions.cpp',
+ 'ajalibraries/ajantv2/src/ntv2supportlogger.cpp',
+ 'ajalibraries/ajantv2/src/ntv2transcode.cpp',
+ 'ajalibraries/ajantv2/src/ntv2utf8.cpp',
+ 'ajalibraries/ajantv2/src/ntv2utils.cpp',
+ 'ajalibraries/ajantv2/src/ntv2verticalfilter.cpp',
+ 'ajalibraries/ajantv2/src/ntv2vpid.cpp',
+ 'ajalibraries/ajantv2/src/ntv2vpidfromspec.cpp',
+ 'ajalibraries/ajantv2/src/ntv2task.cpp',
+ 'ajalibraries/ajantv2/src/ntv2testpatterngen.cpp',
+]
+
+ajantv2_args = [
+ '-D_REENTRANT',
+ '-DAJASTATIC',
+ '-DAJALinux',
+ '-DAJA_LINUX',
+ '-D_LARGEFILE_SOURCE',
+ '-D_LARGEFILE64_SOURCE',
+ '-D_FILE_OFFSET_BITS=64',
+]
+
+ajantv2_inc = include_directories(
+ 'ajalibraries/ajaanc/includes',
+ 'ajalibraries/ajantv2/includes',
+ 'ajalibraries/ajantv2/src',
+ 'ajalibraries/ajantv2/src/lin',
+ 'ajalibraries',
+ 'ajalibraries/ajabase',
+)
+
+libajantv2 = static_library(
+ 'libajantv2',
+ sources: ajantv2_sources,
+ cpp_args: ajantv2_args,
+ include_directories: ajantv2_inc,
+ pic: true,
+ override_options: ['cpp_eh=default', 'werror=false'],
+ install: false
+)
+
+libajantv2_dep = declare_dependency(
+ link_with: libajantv2,
+ include_directories: ajantv2_inc,
+)