OpenShot Library | libopenshot  0.2.7
DecklinkReader.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for DecklinkReader 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 "DecklinkReader.h"
14 #include "Exceptions.h"
15 
16 using namespace openshot;
17 
18 DecklinkReader::DecklinkReader(int device, int video_mode, int pixel_format, int channels, int sample_depth)
19  : device(device), is_open(false), g_videoModeIndex(video_mode), g_audioChannels(channels), g_audioSampleDepth(sample_depth)
20 {
21  // Init decklink variables
22  inputFlags = 0;
23  selectedDisplayMode = bmdModeNTSC;
24  pixelFormat = bmdFormat8BitYUV;
25  displayModeCount = 0;
26  exitStatus = 1;
27  foundDisplayMode = false;
28  pthread_mutex_init(&sleepMutex, NULL);
29  pthread_cond_init(&sleepCond, NULL);
30 
31  switch(pixel_format)
32  {
33  case 0: pixelFormat = bmdFormat8BitYUV; break;
34  case 1: pixelFormat = bmdFormat10BitYUV; break;
35  case 2: pixelFormat = bmdFormat10BitRGB; break;
36  default:
37  throw DecklinkError("Pixel format is not valid (must be 0,1,2).");
38  }
39 
40 
41  // Attempt to open blackmagic card
42  deckLinkIterator = CreateDeckLinkIteratorInstance();
43 
44  if (!deckLinkIterator)
45  throw DecklinkError("This application requires the DeckLink drivers installed.");
46 
47  /* Connect to a DeckLink instance */
48  for (int device_count = 0; device_count <= device; device_count++)
49  {
50  // Check for requested device
51  result = deckLinkIterator->Next(&deckLink);
52  if (result != S_OK)
53  throw DecklinkError("No DeckLink PCI cards found.");
54 
55  if (device_count == device)
56  break;
57  }
58 
59  if (deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput) != S_OK)
60  throw DecklinkError("DeckLink QueryInterface Failed.");
61 
62  // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
63  result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
64  if (result != S_OK)
65  throw DecklinkError("Could not obtain the video output display mode iterator.");
66 
67  // Init deckLinkOutput (needed for color conversion)
68  if (deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&m_deckLinkOutput) != S_OK)
69  throw DecklinkError("Failed to create a deckLinkOutput(), used to convert YUV to RGB.");
70 
71  // Init the YUV to RGB conversion
72  if(!(m_deckLinkConverter = CreateVideoConversionInstance()))
73  throw DecklinkError("Failed to create a VideoConversionInstance(), used to convert YUV to RGB.");
74 
75  // Create Delegate & Pass in pointers to the output and converters
76  delegate = new DeckLinkInputDelegate(&sleepCond, m_deckLinkOutput, m_deckLinkConverter);
77  deckLinkInput->SetCallback(delegate);
78 
79 
80 
81  if (g_videoModeIndex < 0)
82  throw DecklinkError("No video mode specified.");
83 
84  // Loop through all available display modes, until a match is found (if any)
85  while (displayModeIterator->Next(&displayMode) == S_OK)
86  {
87  if (g_videoModeIndex == displayModeCount)
88  {
89  BMDDisplayModeSupport result;
90 
91  foundDisplayMode = true;
92  displayMode->GetName(&displayModeName);
93  selectedDisplayMode = displayMode->GetDisplayMode();
94  deckLinkInput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoInputFlagDefault, &result, NULL);
95 
96  // Get framerate
97  displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
98 
99  if (result == bmdDisplayModeNotSupported)
100  throw DecklinkError("The display mode does not support the selected pixel format.");
101 
102  if (inputFlags & bmdVideoInputDualStream3D)
103  {
104  if (!(displayMode->GetFlags() & bmdDisplayModeSupports3D))
105  throw DecklinkError("The display mode does not support 3D.");
106  }
107 
108  break;
109  }
110  displayModeCount++;
111  displayMode->Release();
112  }
113 
114  if (!foundDisplayMode)
115  throw DecklinkError("Invalid video mode. No matching ones found.");
116 
117  // Check for video input
118  result = deckLinkInput->EnableVideoInput(selectedDisplayMode, pixelFormat, inputFlags);
119  if(result != S_OK)
120  throw DecklinkError("Failed to enable video input. Is another application using the card?");
121 
122  // Check for audio input
123  result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels);
124  if(result != S_OK)
125  throw DecklinkError("Failed to enable audio input. Is another application using the card?");
126 
127 }
128 
129 // destructor
131 {
132  if (displayModeIterator != NULL)
133  {
134  displayModeIterator->Release();
135  displayModeIterator = NULL;
136  }
137 
138  if (deckLinkInput != NULL)
139  {
140  deckLinkInput->Release();
141  deckLinkInput = NULL;
142  }
143 
144  if (deckLink != NULL)
145  {
146  deckLink->Release();
147  deckLink = NULL;
148  }
149 
150  if (deckLinkIterator != NULL)
151  deckLinkIterator->Release();
152 }
153 
154 // Open image file
156 {
157  // Open reader if not already open
158  if (!is_open)
159  {
160  // Start the streams
161  result = deckLinkInput->StartStreams();
162  if(result != S_OK)
163  throw DecklinkError("Failed to start the video and audio streams.");
164 
165 
166  // Update image properties
167  info.has_audio = false;
168  info.has_video = true;
169  info.vcodec = displayModeName;
170  info.width = displayMode->GetWidth();
171  info.height = displayMode->GetHeight();
172  info.file_size = info.width * info.height * sizeof(char) * 4;
173  info.pixel_ratio.num = 1;
174  info.pixel_ratio.den = 1;
175  info.duration = 60 * 60 * 24; // 24 hour duration... since we're capturing a live stream
176  info.fps.num = frameRateScale;
177  info.fps.den = frameRateDuration;
178  info.video_timebase.num = frameRateDuration;
179  info.video_timebase.den = frameRateScale;
181 
182  // Calculate the DAR (display aspect ratio)
184 
185  // Reduce size fraction
186  size.Reduce();
187 
188  // Set the ratio based on the reduced fraction
189  info.display_ratio.num = size.num;
190  info.display_ratio.den = size.den;
191 
192  // Mark as "open"
193  is_open = true;
194  }
195 }
196 
197 // Close device and video stream
199 {
200  // Close all objects, if reader is 'open'
201  if (is_open)
202  {
203  // Stop streams
204  result = deckLinkInput->StopStreams();
205 
206  if(result != S_OK)
207  throw DecklinkError("Failed to stop the video and audio streams.");
208 
209  // Mark as "closed"
210  is_open = false;
211  }
212 }
213 
215 {
216  return delegate->GetCurrentFrameNumber();
217 }
218 
219 // Get an openshot::Frame object for the next available LIVE frame
220 std::shared_ptr<Frame> DecklinkReader::GetFrame(int64_t requested_frame)
221 {
222  // Get a frame from the delegate decklink class (which is collecting them on another thread)
223  std::shared_ptr<Frame> f = delegate->GetFrame(requested_frame);
224 
225 // cout << "Change the frame number to " << requested_frame << endl;
226 // f->SetFrameNumber(requested_frame);
227  return f; // frame # does not matter, since it always gets the oldest frame
228 }
229 
230 
231 // Generate JSON string of this object
232 std::string DecklinkReader::Json() const {
233 
234  // Return formatted string
235  return JsonValue().toStyledString();
236 }
237 
238 // Generate Json::Value for this object
239 Json::Value DecklinkReader::JsonValue() const {
240 
241  // Create root json object
242  Json::Value root = ReaderBase::JsonValue(); // get parent properties
243  root["type"] = "DecklinkReader";
244 
245  // return JsonValue
246  return root;
247 }
248 
249 // Load JSON string into this object
250 void DecklinkReader::SetJson(const std::string value) {
251 
252  // Parse JSON string into JSON objects
253  try
254  {
255  const Json::Value root = openshot::stringToJson(value);
256  // Set all values that match
257  SetJsonValue(root);
258  }
259  catch (const std::exception& e)
260  {
261  // Error parsing JSON (or missing keys)
262  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
263  }
264 }
265 
266 // Load Json::Value into this object
267 void DecklinkReader::SetJsonValue(const Json::Value root) {
268 
269  // Set parent data
271 
272  // Re-Open path, and re-init everything (if needed)
273  if (is_open)
274  {
275  Close();
276  Open();
277  }
278 }
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame)
int num
Numerator for the fraction.
Definition: Fraction.h:32
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
int width
The width of the video (in pixesl)
Definition: ReaderBase.h:48
std::shared_ptr< Frame > GetFrame(int64_t requested_frame)
float duration
Length of time (in seconds)
Definition: ReaderBase.h:45
void Open()
Open device and video stream - which is called by the constructor automatically.
unsigned long GetCurrentFrameNumber()
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:40
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
bool has_video
Determines if this file has a video stream.
Definition: ReaderBase.h:42
std::string Json() const override
Generate JSON string of this object.
int64_t file_size
Size of file (in bytes)
Definition: ReaderBase.h:46
Header file for all Exception classes.
bool has_audio
Determines if this file has an audio stream.
Definition: ReaderBase.h:43
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:104
Implementation of the Blackmagic Decklink API (used by the DecklinkReader)
Definition: DecklinkInput.h:32
Exception when accessing a blackmagic decklink card.
Definition: Exceptions.h:61
int64_t video_length
The number of frames in the video stream.
Definition: ReaderBase.h:55
int height
The height of the video (in pixels)
Definition: ReaderBase.h:47
void SetJson(const std::string value)
Load JSON string into this object.
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: ReaderBase.h:57
This class represents a fraction.
Definition: Fraction.h:30
unsigned long GetCurrentFrameNumber()
DecklinkReader(int device, int video_mode, int pixel_format, int channels, int sample_depth)
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition: ReaderBase.cpp:159
Header file for DecklinkReader class.
Json::Value JsonValue() const
Generate Json::Value for this object.
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:91
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: ReaderBase.h:54
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
Exception for invalid JSON.
Definition: Exceptions.h:187
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3) ...
Definition: ReaderBase.h:53
void Close()
Destructor.
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
Definition: ReaderBase.h:52
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: ReaderBase.h:50