OpenShot Library | libopenshot  0.2.7
DecklinkWriter.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for DecklinkWriter class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @ref License
7  */
8 
9 // Copyright (c) 2008-2019 OpenShot Studios, LLC
10 //
11 // SPDX-License-Identifier: LGPL-3.0-or-later
12 
13 #include "DecklinkWriter.h"
14 
15 using namespace openshot;
16 
17 DecklinkWriter::DecklinkWriter(int device, int video_mode, int pixel_format, int channels, int sample_depth)
18  : device(device), is_open(false), g_videoModeIndex(video_mode), g_audioChannels(channels), g_audioSampleDepth(sample_depth)
19 {
20  // Init decklink variables
21  inputFlags = 0;
22  selectedDisplayMode = bmdModeNTSC;
23  pixelFormat = bmdFormat8BitYUV;
24  displayModeCount = 0;
25  exitStatus = 1;
26  foundDisplayMode = false;
27  pthread_mutex_init(&sleepMutex, NULL);
28  pthread_cond_init(&sleepCond, NULL);
29 
30  switch(pixel_format)
31  {
32  case 0: pixelFormat = bmdFormat8BitYUV; break;
33  case 1: pixelFormat = bmdFormat10BitYUV; break;
34  case 2: pixelFormat = bmdFormat10BitRGB; break;
35  case 3: pixelFormat = bmdFormat8BitARGB; break;
36  default:
37  throw DecklinkError("Pixel format is not valid (must be 0,1,2,3).");
38  }
39 }
40 
41 // Open decklink writer
43 {
44  // Open reader if not already open
45  if (!is_open)
46  {
47  // Attempt to open blackmagic card
48  deckLinkIterator = CreateDeckLinkIteratorInstance();
49 
50  if (!deckLinkIterator)
51  throw DecklinkError("This application requires the DeckLink drivers installed.");
52 
53  /* Connect to a DeckLink instance */
54  for (int device_count = 0; device_count <= device; device_count++)
55  {
56  // Check for requested device
57  result = deckLinkIterator->Next(&deckLink);
58  if (result != S_OK)
59  throw DecklinkError("No DeckLink PCI cards found.");
60 
61  if (device_count == device)
62  break;
63  }
64 
65  if (deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&deckLinkOutput) != S_OK)
66  throw DecklinkError("DeckLink QueryInterface Failed.");
67 
68  // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
69  result = deckLinkOutput->GetDisplayModeIterator(&displayModeIterator);
70  if (result != S_OK)
71  throw DecklinkError("Could not obtain the video output display mode iterator.");
72 
73  if (g_videoModeIndex < 0)
74  throw DecklinkError("No video mode specified.");
75 
76  // Loop through all available display modes, until a match is found (if any)
77  const char *displayModeName;
78  BMDTimeValue frameRateDuration, frameRateScale;
79 
80  while (displayModeIterator->Next(&displayMode) == S_OK)
81  {
82  if (g_videoModeIndex == displayModeCount)
83  {
84  BMDDisplayModeSupport result;
85 
86  foundDisplayMode = true;
87  displayMode->GetName(&displayModeName);
88  selectedDisplayMode = displayMode->GetDisplayMode();
89  //deckLinkOutput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoOutputFlagDefault, &result, NULL);
90 
91  // Get framerate
92  displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
93 
94  //if (result == bmdDisplayModeNotSupported)
95  //{
96  // cout << "The display mode does not support the selected pixel format." << endl;
97  // throw DecklinkError("The display mode does not support the selected pixel format.");
98  //}
99 
100  break;
101  }
102  displayModeCount++;
103  }
104 
105  if (!foundDisplayMode)
106  throw DecklinkError("Invalid video mode. No matching ones found.");
107 
108  // Calculate FPS
109  unsigned long m_framesPerSecond = (unsigned long)((frameRateScale + (frameRateDuration-1)) / frameRateDuration);
110 
111  // Create Delegate & Pass in pointers to the output and converters
112  delegate = new DeckLinkOutputDelegate(displayMode, deckLinkOutput);
113 
114  // Provide this class as a delegate to the audio and video output interfaces
115  deckLinkOutput->SetScheduledFrameCompletionCallback(delegate);
116  //deckLinkOutput->SetAudioCallback(delegate);
117 
118  // Check for video input
119  if (deckLinkOutput->EnableVideoOutput(displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) != S_OK)
120  throw DecklinkError("Failed to enable video output. Is another application using the card?");
121 
122  // Check for audio input
123  //if (deckLinkOutput->EnableAudioOutput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels, bmdAudioOutputStreamContinuous) != S_OK)
124  // throw DecklinkError("Failed to enable audio output. Is another application using the card?");
125 
126  // Begin video preroll by scheduling a second of frames in hardware
127  //auto f = std::make_shared<Frame>(1, displayMode->GetWidth(), displayMode->GetHeight(), "Blue");
128  //f->AddColor(displayMode->GetWidth(), displayMode->GetHeight(), "Blue");
129 
130  // Preroll 1 second of video
131  //for (unsigned i = 0; i < 16; i++)
132  //{
133  // // Write 30 blank frames (for preroll)
134  // delegate->WriteFrame(f);
135  // delegate->ScheduleNextFrame(true);
136  //}
137 
138  //deckLinkOutput->StartScheduledPlayback(0, 100, 1.0);
139  //if (deckLinkOutput->BeginAudioPreroll() != S_OK)
140  // throw DecklinkError("Failed to begin audio preroll.");
141 
142 
143  // Update image properties
144  info.has_audio = true;
145  info.has_video = true;
146  info.vcodec = displayModeName;
147  info.width = displayMode->GetWidth();
148  info.height = displayMode->GetHeight();
149  info.file_size = info.width * info.height * sizeof(char) * 4;
150  info.pixel_ratio.num = 1;
151  info.pixel_ratio.den = 1;
152  info.duration = 60 * 60 * 24; // 24 hour duration... since we're capturing a live stream
153  info.fps.num = frameRateScale;
154  info.fps.den = frameRateDuration;
155  info.video_timebase.num = frameRateDuration;
156  info.video_timebase.den = frameRateScale;
158 
159  // Calculate the DAR (display aspect ratio)
161 
162  // Reduce size fraction
163  size.Reduce();
164 
165  // Set the ratio based on the reduced fraction
166  info.display_ratio.num = size.num;
167  info.display_ratio.den = size.den;
168 
169  // Mark as "open"
170  is_open = true;
171  }
172 }
173 
174 // Close device and video stream
176 {
177  // Close all objects, if reader is 'open'
178  if (is_open)
179  {
180  // Stop the audio and video output streams immediately
181  deckLinkOutput->StopScheduledPlayback(0, NULL, 0);
182  deckLinkOutput->DisableAudioOutput();
183  deckLinkOutput->DisableVideoOutput();
184 
185  // Release DisplayMode
186  displayMode->Release();
187 
188  if (displayModeIterator != NULL)
189  {
190  displayModeIterator->Release();
191  displayModeIterator = NULL;
192  }
193 
194  if (deckLinkOutput != NULL)
195  {
196  deckLinkOutput->Release();
197  deckLinkOutput = NULL;
198  }
199 
200  if (deckLink != NULL)
201  {
202  deckLink->Release();
203  deckLink = NULL;
204  }
205 
206  if (deckLinkIterator != NULL)
207  deckLinkIterator->Release();
208 
209  // Mark as "closed"
210  is_open = false;
211  }
212 }
213 
214 // This method is required for all derived classes of WriterBase. Write a Frame to the video file.
215 void DecklinkWriter::WriteFrame(std::shared_ptr<Frame> frame)
216 {
217  // Check for open reader (or throw exception)
218  if (!is_open)
219  throw WriterClosed("The DecklinkWriter is closed. Call Open() before calling this method.");
220 
221  delegate->WriteFrame(frame);
222 }
223 
224 // This method is required for all derived classes of WriterBase. Write a block of frames from a reader.
225 void DecklinkWriter::WriteFrame(ReaderBase* reader, int start, int length)
226 {
227  // Loop through each frame (and encoded it)
228  for (int number = start; number <= length; number++)
229  {
230  // Get the frame
231  std::shared_ptr<Frame> f = reader->GetFrame(number);
232 
233  // Encode frame
234  WriteFrame(f);
235  }
236 }
void WriteFrame(std::shared_ptr< Frame > frame)
This method is required for all derived classes of WriterBase. Write a Frame to the video file...
int num
Numerator for the fraction.
Definition: Fraction.h:32
Header file for DecklinkWriter class.
WriterInfo info
Information about the current media file.
Definition: WriterBase.h:76
Implementation of the Blackmagic Decklink API (used by the DecklinkWriter)
int64_t video_length
The number of frames in the video stream.
Definition: WriterBase.h:47
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3) ...
Definition: WriterBase.h:45
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:40
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:77
int width
The width of the video (in pixels)
Definition: WriterBase.h:40
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: WriterBase.h:49
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
Definition: WriterBase.h:44
int64_t file_size
Size of file (in bytes)
Definition: WriterBase.h:38
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
float duration
Length of time (in seconds)
Definition: WriterBase.h:37
Exception when accessing a blackmagic decklink card.
Definition: Exceptions.h:61
This class represents a fraction.
Definition: Fraction.h:30
DecklinkWriter(int device, int video_mode, int pixel_format, int channels, int sample_depth)
bool has_video
Determines if this file has a video stream.
Definition: WriterBase.h:34
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Custom method to write new frames.
void Open()
Open device and video stream - which is called by the constructor automatically.
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
void Close()
Close the device and video stream.
bool has_audio
Determines if this file has an audio stream.
Definition: WriterBase.h:35
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: WriterBase.h:46
Exception when too many seek attempts happen.
Definition: Exceptions.h:372
int height
The height of the video (in pixels)
Definition: WriterBase.h:39
int den
Denominator for the fraction.
Definition: Fraction.h:33
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: WriterBase.h:42