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