OpenShot Library | libopenshot  0.2.4
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 /* LICENSE
10  *
11  * Copyright (c) 2008-2019 OpenShot Studios, LLC
12  * <http://www.openshotstudios.com/>. This file is part of
13  * OpenShot Library (libopenshot), an open-source project dedicated to
14  * delivering high quality video editing and animation solutions to the
15  * world. For more information visit <http://www.openshot.org/>.
16  *
17  * OpenShot Library (libopenshot) is free software: you can redistribute it
18  * and/or modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation, either version 3 of the
20  * License, or (at your option) any later version.
21  *
22  * OpenShot Library (libopenshot) is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #include "../include/DecklinkWriter.h"
32 
33 using namespace openshot;
34 
35 DecklinkWriter::DecklinkWriter(int device, int video_mode, int pixel_format, int channels, int sample_depth)
36  : device(device), is_open(false), g_videoModeIndex(video_mode), g_audioChannels(channels), g_audioSampleDepth(sample_depth)
37 {
38  // Init decklink variables
39  inputFlags = 0;
40  selectedDisplayMode = bmdModeNTSC;
41  pixelFormat = bmdFormat8BitYUV;
42  displayModeCount = 0;
43  exitStatus = 1;
44  foundDisplayMode = false;
45  pthread_mutex_init(&sleepMutex, NULL);
46  pthread_cond_init(&sleepCond, NULL);
47 
48  switch(pixel_format)
49  {
50  case 0: pixelFormat = bmdFormat8BitYUV; break;
51  case 1: pixelFormat = bmdFormat10BitYUV; break;
52  case 2: pixelFormat = bmdFormat10BitRGB; break;
53  case 3: pixelFormat = bmdFormat8BitARGB; break;
54  default:
55  throw DecklinkError("Pixel format is not valid (must be 0,1,2,3).");
56  }
57 }
58 
59 // Open decklink writer
61 {
62  // Open reader if not already open
63  if (!is_open)
64  {
65  // Attempt to open blackmagic card
66  deckLinkIterator = CreateDeckLinkIteratorInstance();
67 
68  if (!deckLinkIterator)
69  throw DecklinkError("This application requires the DeckLink drivers installed.");
70 
71  /* Connect to a DeckLink instance */
72  for (int device_count = 0; device_count <= device; device_count++)
73  {
74  // Check for requested device
75  result = deckLinkIterator->Next(&deckLink);
76  if (result != S_OK)
77  throw DecklinkError("No DeckLink PCI cards found.");
78 
79  if (device_count == device)
80  break;
81  }
82 
83  if (deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&deckLinkOutput) != S_OK)
84  throw DecklinkError("DeckLink QueryInterface Failed.");
85 
86  // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
87  result = deckLinkOutput->GetDisplayModeIterator(&displayModeIterator);
88  if (result != S_OK)
89  throw DecklinkError("Could not obtain the video output display mode iterator.");
90 
91  if (g_videoModeIndex < 0)
92  throw DecklinkError("No video mode specified.");
93 
94  // Loop through all available display modes, until a match is found (if any)
95  const char *displayModeName;
96  BMDTimeValue frameRateDuration, frameRateScale;
97 
98  while (displayModeIterator->Next(&displayMode) == S_OK)
99  {
100  if (g_videoModeIndex == displayModeCount)
101  {
102  BMDDisplayModeSupport result;
103 
104  foundDisplayMode = true;
105  displayMode->GetName(&displayModeName);
106  selectedDisplayMode = displayMode->GetDisplayMode();
107  //deckLinkOutput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoOutputFlagDefault, &result, NULL);
108 
109  // Get framerate
110  displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
111 
112  //if (result == bmdDisplayModeNotSupported)
113  //{
114  // cout << "The display mode does not support the selected pixel format." << endl;
115  // throw DecklinkError("The display mode does not support the selected pixel format.");
116  //}
117 
118  break;
119  }
120  displayModeCount++;
121  }
122 
123  if (!foundDisplayMode)
124  throw DecklinkError("Invalid video mode. No matching ones found.");
125 
126  // Calculate FPS
127  unsigned long m_framesPerSecond = (unsigned long)((frameRateScale + (frameRateDuration-1)) / frameRateDuration);
128 
129  // Create Delegate & Pass in pointers to the output and converters
130  delegate = new DeckLinkOutputDelegate(displayMode, deckLinkOutput);
131 
132  // Provide this class as a delegate to the audio and video output interfaces
133  deckLinkOutput->SetScheduledFrameCompletionCallback(delegate);
134  //deckLinkOutput->SetAudioCallback(delegate);
135 
136  // Check for video input
137  if (deckLinkOutput->EnableVideoOutput(displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) != S_OK)
138  throw DecklinkError("Failed to enable video output. Is another application using the card?");
139 
140  // Check for audio input
141  //if (deckLinkOutput->EnableAudioOutput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels, bmdAudioOutputStreamContinuous) != S_OK)
142  // throw DecklinkError("Failed to enable audio output. Is another application using the card?");
143 
144  // Begin video preroll by scheduling a second of frames in hardware
145  //std::shared_ptr<Frame> f(new Frame(1, displayMode->GetWidth(), displayMode->GetHeight(), "Blue"));
146  //f->AddColor(displayMode->GetWidth(), displayMode->GetHeight(), "Blue");
147 
148  // Preroll 1 second of video
149  //for (unsigned i = 0; i < 16; i++)
150  //{
151  // // Write 30 blank frames (for preroll)
152  // delegate->WriteFrame(f);
153  // delegate->ScheduleNextFrame(true);
154  //}
155 
156  //deckLinkOutput->StartScheduledPlayback(0, 100, 1.0);
157  //if (deckLinkOutput->BeginAudioPreroll() != S_OK)
158  // throw DecklinkError("Failed to begin audio preroll.");
159 
160 
161  // Update image properties
162  info.has_audio = true;
163  info.has_video = true;
164  info.vcodec = displayModeName;
165  info.width = displayMode->GetWidth();
166  info.height = displayMode->GetHeight();
167  info.file_size = info.width * info.height * sizeof(char) * 4;
168  info.pixel_ratio.num = 1;
169  info.pixel_ratio.den = 1;
170  info.duration = 60 * 60 * 24; // 24 hour duration... since we're capturing a live stream
171  info.fps.num = frameRateScale;
172  info.fps.den = frameRateDuration;
173  info.video_timebase.num = frameRateDuration;
174  info.video_timebase.den = frameRateScale;
176 
177  // Calculate the DAR (display aspect ratio)
179 
180  // Reduce size fraction
181  size.Reduce();
182 
183  // Set the ratio based on the reduced fraction
184  info.display_ratio.num = size.num;
185  info.display_ratio.den = size.den;
186 
187  // Mark as "open"
188  is_open = true;
189  }
190 }
191 
192 // Close device and video stream
194 {
195  // Close all objects, if reader is 'open'
196  if (is_open)
197  {
198  // Stop the audio and video output streams immediately
199  deckLinkOutput->StopScheduledPlayback(0, NULL, 0);
200  deckLinkOutput->DisableAudioOutput();
201  deckLinkOutput->DisableVideoOutput();
202 
203  // Release DisplayMode
204  displayMode->Release();
205 
206  if (displayModeIterator != NULL)
207  {
208  displayModeIterator->Release();
209  displayModeIterator = NULL;
210  }
211 
212  if (deckLinkOutput != NULL)
213  {
214  deckLinkOutput->Release();
215  deckLinkOutput = NULL;
216  }
217 
218  if (deckLink != NULL)
219  {
220  deckLink->Release();
221  deckLink = NULL;
222  }
223 
224  if (deckLinkIterator != NULL)
225  deckLinkIterator->Release();
226 
227  // Mark as "closed"
228  is_open = false;
229  }
230 }
231 
232 // This method is required for all derived classes of WriterBase. Write a Frame to the video file.
233 void DecklinkWriter::WriteFrame(std::shared_ptr<Frame> frame)
234 {
235  // Check for open reader (or throw exception)
236  if (!is_open)
237  throw WriterClosed("The DecklinkWriter is closed. Call Open() before calling this method.");
238 
239  delegate->WriteFrame(frame);
240 }
241 
242 // This method is required for all derived classes of WriterBase. Write a block of frames from a reader.
243 void DecklinkWriter::WriteFrame(ReaderBase* reader, int start, int length)
244 {
245  // Loop through each frame (and encoded it)
246  for (int number = start; number <= length; number++)
247  {
248  // Get the frame
249  std::shared_ptr<Frame> f = reader->GetFrame(number);
250 
251  // Encode frame
252  WriteFrame(f);
253  }
254 }
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:47
WriterInfo info
Information about the current media file.
Definition: WriterBase.h:94
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:65
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:63
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:97
int width
The width of the video (in pixels)
Definition: WriterBase.h:58
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: WriterBase.h:67
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
Definition: WriterBase.h:62
int64_t file_size
Size of file (in bytes)
Definition: WriterBase.h:56
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
float duration
Length of time (in seconds)
Definition: WriterBase.h:55
Exception when accessing a blackmagic decklink card.
Definition: Exceptions.h:79
This class represents a fraction.
Definition: Fraction.h:45
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:52
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.
void Close()
Close the device and video stream.
bool has_audio
Determines if this file has an audio stream.
Definition: WriterBase.h:53
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: WriterBase.h:64
Exception when a writer is closed, and a frame is requested.
Definition: Exceptions.h:385
int height
The height of the video (in pixels)
Definition: WriterBase.h:57
int den
Denominator for the fraction.
Definition: Fraction.h:48
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: WriterBase.h:60
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:49