OpenShot Library | libopenshot  0.2.5
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 /* LICENSE
10  *
11  * Copyright (c) 2009 Blackmagic Design
12  *
13  * Permission is hereby granted, free of charge, to any person or organization
14  * obtaining a copy of the software and accompanying documentation covered by
15  * this license (the "Software") to use, reproduce, display, distribute,
16  * execute, and transmit the Software, and to prepare derivative works of the
17  * Software, and to permit third-parties to whom the Software is furnished to
18  * do so, all subject to the following:
19  *
20  * The copyright notices in the Software and this entire statement, including
21  * the above license grant, this restriction and the following disclaimer,
22  * must be included in all copies of the Software, in whole or in part, and
23  * all derivative works of the Software, unless such copies or derivative
24  * works are solely in the form of machine-executable object code generated by
25  * a source language processor.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
30  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
31  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33  * DEALINGS IN THE SOFTWARE.
34  *
35  *
36  * Copyright (c) 2008-2019 OpenShot Studios, LLC
37  * <http://www.openshotstudios.com/>. This file is part of
38  * OpenShot Library (libopenshot), an open-source project dedicated to
39  * delivering high quality video editing and animation solutions to the
40  * world. For more information visit <http://www.openshot.org/>.
41  *
42  * OpenShot Library (libopenshot) is free software: you can redistribute it
43  * and/or modify it under the terms of the GNU Lesser General Public License
44  * as published by the Free Software Foundation, either version 3 of the
45  * License, or (at your option) any later version.
46  *
47  * OpenShot Library (libopenshot) is distributed in the hope that it will be
48  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50  * GNU Lesser General Public License for more details.
51  *
52  * You should have received a copy of the GNU Lesser General Public License
53  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
54  */
55 
56 #include "../include/DecklinkInput.h"
57 
58 using namespace std;
59 
60 DeckLinkInputDelegate::DeckLinkInputDelegate(pthread_cond_t* m_sleepCond, IDeckLinkOutput* m_deckLinkOutput, IDeckLinkVideoConversion* m_deckLinkConverter)
61  : m_refCount(0), g_timecodeFormat(0), frameCount(0), final_frameCount(0)
62 {
63  sleepCond = m_sleepCond;
64  deckLinkOutput = m_deckLinkOutput;
65  deckLinkConverter = m_deckLinkConverter;
66 
67  // Set cache size (20 1080p frames)
68  final_frames.SetMaxBytes(60 * 1920 * 1080 * 4 + (44100 * 2 * 4));
69 
70  pthread_mutex_init(&m_mutex, NULL);
71 }
72 
74 {
75  pthread_mutex_destroy(&m_mutex);
76 }
77 
79 {
80  pthread_mutex_lock(&m_mutex);
81  m_refCount++;
82  pthread_mutex_unlock(&m_mutex);
83 
84  return (ULONG)m_refCount;
85 }
86 
88 {
89  pthread_mutex_lock(&m_mutex);
90  m_refCount--;
91  pthread_mutex_unlock(&m_mutex);
92 
93  if (m_refCount == 0)
94  {
95  delete this;
96  return 0;
97  }
98 
99  return (ULONG)m_refCount;
100 }
101 
103 {
104  if (final_frameCount > 0)
105  return final_frameCount - 1;
106  else
107  return 0;
108 }
109 
110 std::shared_ptr<openshot::Frame> DeckLinkInputDelegate::GetFrame(int64_t requested_frame)
111 {
112  std::shared_ptr<openshot::Frame> f;
113 
114  // Is this frame for the future?
115  while (requested_frame > GetCurrentFrameNumber())
116  {
117  usleep(500 * 1);
118  }
119 
120  #pragma omp critical (blackmagic_input_queue)
121  {
122  if (final_frames.Exists(requested_frame))
123  {
124  // Get the frame and remove it from the cache
125  f = final_frames.GetFrame(requested_frame);
126  final_frames.Remove(requested_frame);
127  }
128  else
129  {
130  cout << "Can't find " << requested_frame << ", GetCurrentFrameNumber(): " << GetCurrentFrameNumber() << endl;
131  final_frames.Display();
132  }
133  }
134 
135  return f;
136 }
137 
138 HRESULT DeckLinkInputDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
139 {
140  // Handle Video Frame
141  if(videoFrame)
142  {
143 
144  if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
145  {
146  fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
147  }
148  else
149  {
150  const char *timecodeString = NULL;
151  if (g_timecodeFormat != 0)
152  {
153  IDeckLinkTimecode *timecode;
154  if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK)
155  {
156  timecode->GetString(&timecodeString);
157  }
158  }
159 
160 // fprintf(stderr, "Frame received (#%lu) [%s] - Size: %li bytes\n",
161 // frameCount,
162 // timecodeString != NULL ? timecodeString : "No timecode",
163 // videoFrame->GetRowBytes() * videoFrame->GetHeight());
164 
165  if (timecodeString)
166  free((void*)timecodeString);
167 
168  // Create a new copy of the YUV frame object
169  IDeckLinkMutableVideoFrame *m_yuvFrame = NULL;
170 
171  int width = videoFrame->GetWidth();
172  int height = videoFrame->GetHeight();
173 
174  HRESULT res = deckLinkOutput->CreateVideoFrame(
175  width,
176  height,
177  videoFrame->GetRowBytes(),
178  bmdFormat8BitYUV,
179  bmdFrameFlagDefault,
180  &m_yuvFrame);
181 
182  // Copy pixel and audio to copied frame
183  void *frameBytesSource;
184  void *frameBytesDest;
185  videoFrame->GetBytes(&frameBytesSource);
186  m_yuvFrame->GetBytes(&frameBytesDest);
187  memcpy(frameBytesDest, frameBytesSource, videoFrame->GetRowBytes() * height);
188 
189  // Add raw YUV frame to queue
190  raw_video_frames.push_back(m_yuvFrame);
191 
192  // Process frames once we have a few (to take advantage of multiple threads)
193  int number_to_process = raw_video_frames.size();
194  if (number_to_process >= OPEN_MP_NUM_PROCESSORS)
195  {
196 
197 //omp_set_num_threads(1);
198 omp_set_nested(true);
199 #pragma omp parallel
200 {
201 #pragma omp single
202 {
203  // Temp frame counters (to keep the frames in order)
204  //frameCount = 0;
205 
206  // Loop through each queued image frame
207  while (!raw_video_frames.empty())
208  {
209  // Get front frame (from the queue)
210  IDeckLinkMutableVideoFrame* frame = raw_video_frames.front();
211  raw_video_frames.pop_front();
212 
213  // declare local variables (for OpenMP)
214  IDeckLinkOutput *copy_deckLinkOutput(deckLinkOutput);
215  IDeckLinkVideoConversion *copy_deckLinkConverter(deckLinkConverter);
216  unsigned long copy_frameCount(frameCount);
217 
218  #pragma omp task firstprivate(copy_deckLinkOutput, copy_deckLinkConverter, frame, copy_frameCount)
219  {
220  // *********** CONVERT YUV source frame to RGB ************
221  void *frameBytes;
222  void *audioFrameBytes;
223 
224  // Create a new RGB frame object
225  IDeckLinkMutableVideoFrame *m_rgbFrame = NULL;
226 
227  int width = videoFrame->GetWidth();
228  int height = videoFrame->GetHeight();
229 
230  HRESULT res = copy_deckLinkOutput->CreateVideoFrame(
231  width,
232  height,
233  width * 4,
234  bmdFormat8BitARGB,
235  bmdFrameFlagDefault,
236  &m_rgbFrame);
237 
238  if(res != S_OK)
239  cout << "BMDOutputDelegate::StartRunning: Error creating RGB frame, res:" << res << endl;
240 
241  // Create a RGB version of this YUV video frame
242  copy_deckLinkConverter->ConvertFrame(frame, m_rgbFrame);
243 
244  // Get RGB Byte array
245  m_rgbFrame->GetBytes(&frameBytes);
246 
247  // *********** CREATE OPENSHOT FRAME **********
248  std::shared_ptr<openshot::Frame> f(new openshot::Frame(copy_frameCount, width, height, "#000000", 2048, 2));
249 
250  // Add Image data to openshot frame
251  // TODO: Fix Decklink support with QImage Upgrade
252  //f->AddImage(width, height, "ARGB", Magick::CharPixel, (uint8_t*)frameBytes);
253 
254  #pragma omp critical (blackmagic_input_queue)
255  {
256  // Add processed frame to cache (to be recalled in order after the thread pool is done)
257  final_frames.Add(f);
258  }
259 
260  // Release RGB data
261  if (m_rgbFrame)
262  m_rgbFrame->Release();
263  // Release RGB data
264  if (frame)
265  frame->Release();
266 
267  } // end task
268 
269  // Increment frame count
270  frameCount++;
271 
272  } // end while
273 
274 } // omp single
275 } // omp parallel
276 
277  // Update final frameCount (since they are done processing now)
278  final_frameCount += number_to_process;
279 
280 
281  } // if size > num processors
282  } // has video source
283  } // if videoFrame
284 
285  return S_OK;
286 }
287 
288 HRESULT DeckLinkInputDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
289 {
290  return S_OK;
291 }
292 
293 
294 
DeckLinkInputDelegate::final_frameCount
unsigned long final_frameCount
Definition: DecklinkInput.h:79
DeckLinkInputDelegate::g_timecodeFormat
BMDTimecodeFormat g_timecodeFormat
Definition: DecklinkInput.h:77
openshot::CacheMemory::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
Definition: CacheMemory.cpp:150
openshot::CacheMemory::Add
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
Definition: CacheMemory.cpp:125
DeckLinkInputDelegate::sleepCond
pthread_cond_t * sleepCond
Definition: DecklinkInput.h:76
DeckLinkInputDelegate::deckLinkOutput
IDeckLinkOutput * deckLinkOutput
Definition: DecklinkInput.h:86
openshot::CacheMemory::Remove
void Remove(int64_t frame_number)
Remove a specific frame.
Definition: CacheMemory.cpp:206
openshot::Frame
This class represents a single frame of video (i.e. image & audio data)
Definition: Frame.h:106
DeckLinkInputDelegate::~DeckLinkInputDelegate
~DeckLinkInputDelegate()
Definition: DecklinkInput.cpp:73
DeckLinkInputDelegate::raw_video_frames
std::deque< IDeckLinkMutableVideoFrame * > raw_video_frames
Definition: DecklinkInput.h:82
DeckLinkInputDelegate::VideoInputFormatChanged
virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode *, BMDDetectedVideoInputFormatFlags)
Definition: DecklinkInput.cpp:288
DeckLinkInputDelegate::DeckLinkInputDelegate
DeckLinkInputDelegate(pthread_cond_t *m_sleepCond, IDeckLinkOutput *deckLinkOutput, IDeckLinkVideoConversion *deckLinkConverter)
Definition: DecklinkInput.cpp:60
OPEN_MP_NUM_PROCESSORS
#define OPEN_MP_NUM_PROCESSORS
Definition: OpenMPUtilities.h:41
DeckLinkInputDelegate::frameCount
unsigned long frameCount
Definition: DecklinkInput.h:78
DeckLinkInputDelegate::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame)
Definition: DecklinkInput.cpp:110
DeckLinkInputDelegate::AddRef
virtual ULONG STDMETHODCALLTYPE AddRef(void)
Definition: DecklinkInput.cpp:78
DeckLinkInputDelegate::GetCurrentFrameNumber
unsigned long GetCurrentFrameNumber()
Definition: DecklinkInput.cpp:102
DeckLinkInputDelegate::Release
virtual ULONG STDMETHODCALLTYPE Release(void)
Definition: DecklinkInput.cpp:87
openshot::CacheBase::SetMaxBytes
void SetMaxBytes(int64_t number_of_bytes)
Set maximum bytes to a different amount.
Definition: CacheBase.h:101
DeckLinkInputDelegate::deckLinkConverter
IDeckLinkVideoConversion * deckLinkConverter
Definition: DecklinkInput.h:87
DeckLinkInputDelegate::VideoInputFrameArrived
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *, IDeckLinkAudioInputPacket *)
Definition: DecklinkInput.cpp:138
DeckLinkInputDelegate::final_frames
openshot::CacheMemory final_frames
Definition: DecklinkInput.h:83