OpenShot Library | libopenshot  0.2.7
DecklinkInput.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for DecklinkInput class
4  * @author Jonathan Thomas <jonathan@openshot.org>, Blackmagic Design
5  *
6  * @ref License
7  */
8 
9 // Copyright (c) 2008-2019 OpenShot Studios, LLC
10 // Copyright (c) 2009 Blackmagic Design
11 //
12 // SPDX-License-Identifier: LGPL-3.0-or-later
13 // SPDX-License-Identifier: MIT
14 
15 #include "DecklinkInput.h"
16 
17 using namespace std;
18 
19 DeckLinkInputDelegate::DeckLinkInputDelegate(pthread_cond_t* m_sleepCond, IDeckLinkOutput* m_deckLinkOutput, IDeckLinkVideoConversion* m_deckLinkConverter)
20  : m_refCount(0), g_timecodeFormat(0), frameCount(0), final_frameCount(0)
21 {
22  sleepCond = m_sleepCond;
23  deckLinkOutput = m_deckLinkOutput;
24  deckLinkConverter = m_deckLinkConverter;
25 
26  // Set cache size (20 1080p frames)
27  final_frames.SetMaxBytes(60 * 1920 * 1080 * 4 + (44100 * 2 * 4));
28 
29  pthread_mutex_init(&m_mutex, NULL);
30 }
31 
33 {
34  pthread_mutex_destroy(&m_mutex);
35 }
36 
38 {
39  pthread_mutex_lock(&m_mutex);
40  m_refCount++;
41  pthread_mutex_unlock(&m_mutex);
42 
43  return (ULONG)m_refCount;
44 }
45 
47 {
48  pthread_mutex_lock(&m_mutex);
49  m_refCount--;
50  pthread_mutex_unlock(&m_mutex);
51 
52  if (m_refCount == 0)
53  {
54  delete this;
55  return 0;
56  }
57 
58  return (ULONG)m_refCount;
59 }
60 
62 {
63  if (final_frameCount > 0)
64  return final_frameCount - 1;
65  else
66  return 0;
67 }
68 
69 std::shared_ptr<openshot::Frame> DeckLinkInputDelegate::GetFrame(int64_t requested_frame)
70 {
71  std::shared_ptr<openshot::Frame> f;
72 
73  // Is this frame for the future?
74  while (requested_frame > GetCurrentFrameNumber())
75  {
76  usleep(500 * 1);
77  }
78 
79  #pragma omp critical (blackmagic_input_queue)
80  {
81  if (final_frames.Exists(requested_frame))
82  {
83  // Get the frame and remove it from the cache
84  f = final_frames.GetFrame(requested_frame);
85  final_frames.Remove(requested_frame);
86  }
87  else
88  {
89  cout << "Can't find " << requested_frame << ", GetCurrentFrameNumber(): " << GetCurrentFrameNumber() << endl;
90  final_frames.Display();
91  }
92  }
93 
94  return f;
95 }
96 
97 HRESULT DeckLinkInputDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
98 {
99  // Handle Video Frame
100  if(videoFrame)
101  {
102 
103  if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
104  {
105  fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
106  }
107  else
108  {
109  const char *timecodeString = NULL;
110  if (g_timecodeFormat != 0)
111  {
112  IDeckLinkTimecode *timecode;
113  if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK)
114  {
115  timecode->GetString(&timecodeString);
116  }
117  }
118 
119 // fprintf(stderr, "Frame received (#%lu) [%s] - Size: %li bytes\n",
120 // frameCount,
121 // timecodeString != NULL ? timecodeString : "No timecode",
122 // videoFrame->GetRowBytes() * videoFrame->GetHeight());
123 
124  if (timecodeString)
125  free((void*)timecodeString);
126 
127  // Create a new copy of the YUV frame object
128  IDeckLinkMutableVideoFrame *m_yuvFrame = NULL;
129 
130  int width = videoFrame->GetWidth();
131  int height = videoFrame->GetHeight();
132 
133  HRESULT res = deckLinkOutput->CreateVideoFrame(
134  width,
135  height,
136  videoFrame->GetRowBytes(),
137  bmdFormat8BitYUV,
138  bmdFrameFlagDefault,
139  &m_yuvFrame);
140 
141  // Copy pixel and audio to copied frame
142  void *frameBytesSource;
143  void *frameBytesDest;
144  videoFrame->GetBytes(&frameBytesSource);
145  m_yuvFrame->GetBytes(&frameBytesDest);
146  memcpy(frameBytesDest, frameBytesSource, videoFrame->GetRowBytes() * height);
147 
148  // Add raw YUV frame to queue
149  raw_video_frames.push_back(m_yuvFrame);
150 
151  // Process frames once we have a few (to take advantage of multiple threads)
152  int number_to_process = raw_video_frames.size();
153  if (number_to_process >= OPEN_MP_NUM_PROCESSORS)
154  {
155 
156 //omp_set_num_threads(1);
157 omp_set_nested(true);
158 #pragma omp parallel
159 {
160 #pragma omp single
161 {
162  // Temp frame counters (to keep the frames in order)
163  //frameCount = 0;
164 
165  // Loop through each queued image frame
166  while (!raw_video_frames.empty())
167  {
168  // Get front frame (from the queue)
169  IDeckLinkMutableVideoFrame* frame = raw_video_frames.front();
170  raw_video_frames.pop_front();
171 
172  // declare local variables (for OpenMP)
173  IDeckLinkOutput *copy_deckLinkOutput(deckLinkOutput);
174  IDeckLinkVideoConversion *copy_deckLinkConverter(deckLinkConverter);
175  unsigned long copy_frameCount(frameCount);
176 
177  #pragma omp task firstprivate(copy_deckLinkOutput, copy_deckLinkConverter, frame, copy_frameCount)
178  {
179  // *********** CONVERT YUV source frame to RGB ************
180  void *frameBytes;
181  void *audioFrameBytes;
182 
183  // Create a new RGB frame object
184  IDeckLinkMutableVideoFrame *m_rgbFrame = NULL;
185 
186  int width = videoFrame->GetWidth();
187  int height = videoFrame->GetHeight();
188 
189  HRESULT res = copy_deckLinkOutput->CreateVideoFrame(
190  width,
191  height,
192  width * 4,
193  bmdFormat8BitARGB,
194  bmdFrameFlagDefault,
195  &m_rgbFrame);
196 
197  if(res != S_OK)
198  cout << "BMDOutputDelegate::StartRunning: Error creating RGB frame, res:" << res << endl;
199 
200  // Create a RGB version of this YUV video frame
201  copy_deckLinkConverter->ConvertFrame(frame, m_rgbFrame);
202 
203  // Get RGB Byte array
204  m_rgbFrame->GetBytes(&frameBytes);
205 
206  // *********** CREATE OPENSHOT FRAME **********
207  auto f = std::make_shared<openshot::Frame>(
208  copy_frameCount, width, height, "#000000", 2048, 2);
209 
210  // Add Image data to openshot frame
211  // TODO: Fix Decklink support with QImage Upgrade
212  //f->AddImage(width, height, "ARGB", Magick::CharPixel, (uint8_t*)frameBytes);
213 
214  #pragma omp critical (blackmagic_input_queue)
215  {
216  // Add processed frame to cache (to be recalled in order after the thread pool is done)
217  final_frames.Add(f);
218  }
219 
220  // Release RGB data
221  if (m_rgbFrame)
222  m_rgbFrame->Release();
223  // Release RGB data
224  if (frame)
225  frame->Release();
226 
227  } // end task
228 
229  // Increment frame count
230  frameCount++;
231 
232  } // end while
233 
234 } // omp single
235 } // omp parallel
236 
237  // Update final frameCount (since they are done processing now)
238  final_frameCount += number_to_process;
239 
240 
241  } // if size > num processors
242  } // has video source
243  } // if videoFrame
244 
245  return S_OK;
246 }
247 
248 HRESULT DeckLinkInputDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
249 {
250  return S_OK;
251 }
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame)
virtual ULONG STDMETHODCALLTYPE AddRef(void)
Header file for DecklinkInput class.
STL namespace.
std::deque< IDeckLinkMutableVideoFrame * > raw_video_frames
Definition: DecklinkInput.h:41
#define OPEN_MP_NUM_PROCESSORS
virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode *, BMDDetectedVideoInputFormatFlags)
DeckLinkInputDelegate(pthread_cond_t *m_sleepCond, IDeckLinkOutput *deckLinkOutput, IDeckLinkVideoConversion *deckLinkConverter)
unsigned long frameCount
Definition: DecklinkInput.h:37
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *, IDeckLinkAudioInputPacket *)
unsigned long GetCurrentFrameNumber()
openshot::CacheMemory final_frames
Definition: DecklinkInput.h:42
virtual ULONG STDMETHODCALLTYPE Release(void)
void SetMaxBytes(int64_t number_of_bytes)
Set maximum bytes to a different amount.
Definition: CacheBase.h:82
unsigned long final_frameCount
Definition: DecklinkInput.h:38
BMDTimecodeFormat g_timecodeFormat
Definition: DecklinkInput.h:36
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
pthread_cond_t * sleepCond
Definition: DecklinkInput.h:35
void Remove(int64_t frame_number)
Remove a specific frame.
IDeckLinkOutput * deckLinkOutput
Definition: DecklinkInput.h:45
IDeckLinkVideoConversion * deckLinkConverter
Definition: DecklinkInput.h:46