Skip to content

Commit

Permalink
Merge pull request #247 from tv2/SOF-2119/ableToSetNextInAtem
Browse files Browse the repository at this point in the history
SOF-2119 Able to set Preview in VideoMixer
  • Loading branch information
LindvedKrvang authored Aug 22, 2024
2 parents 2c0a01c + 92b4927 commit 5573679
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/tv2-common/videoSwitchers/Atem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Atem extends VideoSwitcherBase {
public getMixEffectTimelineObject(props: MixEffectProps): TSR.TimelineObjAtemME & TimelineBlueprintExt {
const { content } = props
const me: TSR.TimelineObjAtemME['content']['me'] =
content.input && content.transition
content.input && content.transition && content.transition !== TransitionStyle.CUT
? {
input: this.getInputNumber(content.input),
transition: this.getTransition(content.transition),
Expand Down
20 changes: 20 additions & 0 deletions src/tv2-common/videoSwitchers/VideoSwitcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AuxProps,
DskProps,
DveProps,
getTimeFromFrames,
MixEffectProps,
OnAirMixEffectProps,
SpecialInput,
Expand Down Expand Up @@ -53,6 +54,25 @@ export abstract class VideoSwitcherBase implements VideoSwitcher {
layer: this.uniformConfig.switcherLLayers.primaryMixEffect
})
)

// In order to set the preview we need to create another TimelineObject after the transition is over that sets program and preview.
if (properties.content.transitionDuration) {
// We need a slight delay before we tell the VideoMixer to set the next source, else we risk that the VideoMixer sets the next source in program.
const previewTimelineObjectDelay: number = 300
result.push(
this.getMixEffectTimelineObject({
...properties,
id: primaryId + Math.floor(Math.random() * 10000),
layer: this.uniformConfig.switcherLLayers.primaryMixEffect,
enable: { start: getTimeFromFrames(properties.content.transitionDuration) + previewTimelineObjectDelay },
content: {
input: properties.content.input,
transition: undefined
}
})
)
}

if (this.uniformConfig.switcherLLayers.primaryMixEffectClone) {
result.push(
this.getMixEffectTimelineObject({
Expand Down
5 changes: 2 additions & 3 deletions src/tv2-common/videoSwitchers/__tests__/Atem.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('ATEM', () => {
})
})

test('sets input when CUT transition provided', () => {
test('sets programInput when CUT transition provided', () => {
const atem = createTestee()
const timelineObject = atem.getMixEffectTimelineObject({
layer: SwitcherMixEffectLLayer.PROGRAM,
Expand All @@ -92,8 +92,7 @@ describe('ATEM', () => {
expect(timelineObject).toMatchObject({
content: {
me: {
input: 5,
transition: TSR.AtemTransitionStyle.CUT
programInput: 5
}
}
})
Expand Down
30 changes: 15 additions & 15 deletions src/tv2_afvd_showstyle/__tests__/transitions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function testNotes(context: SegmentUserContextMock) {
}

describe('Primary Cue Transitions Without Config', () => {
it('Cuts by default for KAM', async () => {
it('Transition is undefined by default for KAM', async () => {
const ingestSegment = _.clone(templateSegment)

ingestSegment.payload.iNewsStory.body = '\r\n<p><pi>KAM 1</pi><p>'
Expand All @@ -138,7 +138,7 @@ describe('Primary Cue Transitions Without Config', () => {
const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmCam)
const atemCutObj = getATEMMEObj(piece)

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds effekt to KAM', async () => {
Expand All @@ -156,7 +156,7 @@ describe('Primary Cue Transitions Without Config', () => {

checkPartExistsWithProperties(segment, getTransitionProperties(MOCK_EFFEKT_2))

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds mix to KAM', async () => {
Expand All @@ -183,7 +183,7 @@ describe('Primary Cue Transitions Without Config', () => {
expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(11)
})

it('Cuts by default for EVS1', async () => {
it('Transition is undefined by default for EVS1', async () => {
const ingestSegment = _.clone(templateSegment)

ingestSegment.payload.iNewsStory.body = '\r\n<p><pi>EVS 1</pi><p>'
Expand All @@ -196,7 +196,7 @@ describe('Primary Cue Transitions Without Config', () => {
const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmLocal)
const atemCutObj = getATEMMEObj(piece)

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds effekt to EVS1', async () => {
Expand All @@ -213,7 +213,7 @@ describe('Primary Cue Transitions Without Config', () => {
const atemCutObj = getATEMMEObj(piece)

checkPartExistsWithProperties(segment, getTransitionProperties(MOCK_EFFEKT_1))
expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds mix to EVS1', async () => {
Expand All @@ -240,7 +240,7 @@ describe('Primary Cue Transitions Without Config', () => {
expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(15)
})

it('Cuts by default for EVS1VO', async () => {
it('Transition is undefined by default for EVS1VO', async () => {
const ingestSegment = _.clone(templateSegment)

ingestSegment.payload.iNewsStory.body = '\r\n<p><pi>EVS1VO</pi><p>'
Expand All @@ -253,7 +253,7 @@ describe('Primary Cue Transitions Without Config', () => {
const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmLocal)
const atemCutObj = getATEMMEObj(piece)

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds effekt to EVS1VO', async () => {
Expand All @@ -270,7 +270,7 @@ describe('Primary Cue Transitions Without Config', () => {
const atemCutObj = getATEMMEObj(piece)

checkPartExistsWithProperties(segment, getTransitionProperties(MOCK_EFFEKT_1))
expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds mix to EVS1VO', async () => {
Expand All @@ -297,7 +297,7 @@ describe('Primary Cue Transitions Without Config', () => {
expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(25)
})

it('Cuts by default for SERVER', async () => {
it('Transition is undefined by default for SERVER', async () => {
const ingestSegment = _.clone(templateSegment)

ingestSegment.payload.iNewsStory.body = '\r\n<p><pi>SERVER</pi><p>'
Expand All @@ -310,7 +310,7 @@ describe('Primary Cue Transitions Without Config', () => {
const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmServer)
const atemCutObj = getATEMMEObj(piece)

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds effekt to SERVER', async () => {
Expand All @@ -327,7 +327,7 @@ describe('Primary Cue Transitions Without Config', () => {
const atemCutObj = getATEMMEObj(piece)

checkPartExistsWithProperties(segment, getTransitionProperties(MOCK_EFFEKT_2))
expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds mix to SERVER', async () => {
Expand All @@ -354,7 +354,7 @@ describe('Primary Cue Transitions Without Config', () => {
expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(20)
})

it('Cuts by default for VO', async () => {
it('Transition is undefined by default for VO', async () => {
const ingestSegment = _.clone(templateSegment)

ingestSegment.payload.iNewsStory.body = '\r\n<p><pi>VO</pi><p>'
Expand All @@ -367,7 +367,7 @@ describe('Primary Cue Transitions Without Config', () => {
const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmVoiceOver)
const atemCutObj = getATEMMEObj(piece)

expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds effekt to VO', async () => {
Expand All @@ -384,7 +384,7 @@ describe('Primary Cue Transitions Without Config', () => {
const atemCutObj = getATEMMEObj(piece)

checkPartExistsWithProperties(segment, getTransitionProperties(MOCK_EFFEKT_1))
expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemCutObj.content.me.transition).toBe(undefined)
})

it('Adds mix to VO', async () => {
Expand Down
12 changes: 6 additions & 6 deletions src/tv2_offtube_showstyle/__tests__/actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,10 @@ function getATEMMEObj(piece: IBlueprintPieceInstance): TSR.TimelineObjAtemME {
return atemObj!
}

function expectATEMToCut(piece: IBlueprintPieceInstance) {
function expectUndefinedTransition(piece: IBlueprintPieceInstance): void {
const atemObj = getATEMMEObj(piece)

expect(atemObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT)
expect(atemObj.content.me.transition).toBe(undefined)
}

function expectATEMToMixOver(piece: IBlueprintPieceInstance, frames: number) {
Expand Down Expand Up @@ -956,7 +956,7 @@ describe('Combination Actions', () => {

validateNextPartExistsWithDuration(context, 0)
validateCameraPiece(camPiece)
expectATEMToCut(camPiece!)
expectUndefinedTransition(camPiece!)

await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition)

Expand Down Expand Up @@ -999,7 +999,7 @@ describe('Combination Actions', () => {

validateNextPartExistsWithDuration(context, 0)
validateCameraPiece(camPiece)
expectATEMToCut(camPiece!)
expectUndefinedTransition(camPiece!)

await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition)

Expand Down Expand Up @@ -1042,7 +1042,7 @@ describe('Combination Actions', () => {

validateNextPartExistsWithDuration(context, 0)
validateCameraPiece(camPiece)
expectATEMToCut(camPiece!)
expectUndefinedTransition(camPiece!)

await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition)

Expand Down Expand Up @@ -1085,7 +1085,7 @@ describe('Combination Actions', () => {

validateNextPartExistsWithDuration(context, 0)
validateCameraPiece(camPiece)
expectATEMToCut(camPiece!)
expectUndefinedTransition(camPiece!)

await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition)

Expand Down

0 comments on commit 5573679

Please sign in to comment.