OpenShot Library | libopenshot  0.1.3
Frame.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for Frame class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @section LICENSE
7  *
8  * Copyright (c) 2008-2014 OpenShot Studios, LLC
9  * <http://www.openshotstudios.com/>. This file is part of
10  * OpenShot Library (libopenshot), an open-source project dedicated to
11  * delivering high quality video editing and animation solutions to the
12  * world. For more information visit <http://www.openshot.org/>.
13  *
14  * OpenShot Library (libopenshot) is free software: you can redistribute it
15  * and/or modify it under the terms of the GNU Lesser General Public License
16  * as published by the Free Software Foundation, either version 3 of the
17  * License, or (at your option) any later version.
18  *
19  * OpenShot Library (libopenshot) is distributed in the hope that it will be
20  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
26  */
27 
28 #include "../include/Frame.h"
29 
30 using namespace std;
31 using namespace openshot;
32 
33 // Constructor - blank frame (300x200 blank image, 48kHz audio silence)
34 Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1),
35  channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false)
36 {
37  // Init the image magic and audio buffer
38  audio = tr1::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, 0));
39 
40  // initialize the audio samples to zero (silence)
41  audio->clear();
42 };
43 
44 // Constructor - image only (48kHz audio silence)
45 Frame::Frame(long int number, int width, int height, string color)
46  : number(number), pixel_ratio(1,1), channels(2), width(width), height(height),
47  channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false)
48 {
49  // Init the image magic and audio buffer
50  audio = tr1::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, 0));
51 
52  // initialize the audio samples to zero (silence)
53  audio->clear();
54 };
55 
56 // Constructor - audio only (300x200 blank image)
57 Frame::Frame(long int number, int samples, int channels) :
58  number(number), pixel_ratio(1,1), channels(channels), width(1), height(1),
59  channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false)
60 {
61  // Init the image magic and audio buffer
62  audio = tr1::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, samples));
63 
64  // initialize the audio samples to zero (silence)
65  audio->clear();
66 };
67 
68 // Constructor - image & audio
69 Frame::Frame(long int number, int width, int height, string color, int samples, int channels)
70  : number(number), pixel_ratio(1,1), channels(channels), width(width), height(height),
71  channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false)
72 {
73  // Init the image magic and audio buffer
74  audio = tr1::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, samples));
75 
76  // initialize the audio samples to zero (silence)
77  audio->clear();
78 };
79 
80 
81 // Copy constructor
82 Frame::Frame ( const Frame &other )
83 {
84  // copy pointers and data
85  DeepCopy(other);
86 }
87 
88 // Copy data and pointers from another Frame instance
89 void Frame::DeepCopy(const Frame& other)
90 {
91  number = other.number;
92  image = tr1::shared_ptr<QImage>(new QImage(*(other.image)));
93  audio = tr1::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(*(other.audio)));
94  pixel_ratio = Fraction(other.pixel_ratio.num, other.pixel_ratio.den);
95  channels = other.channels;
96  channel_layout = other.channel_layout;
99  sample_rate = other.sample_rate;
100 
101 
102  if (other.wave_image)
103  wave_image = tr1::shared_ptr<QImage>(new QImage(*(other.wave_image)));
104 }
105 
106 // Descructor
108  // Clear all pointers
109  image.reset();
110  audio.reset();
111 }
112 
113 // Display the frame image to the screen (primarily used for debugging reasons)
115 {
116  if (!QApplication::instance()) {
117  // Only create the QApplication once
118  static int argc = 1;
119  static char* argv[1] = {NULL};
120  previewApp = tr1::shared_ptr<QApplication>(new QApplication(argc, argv));
121  }
122 
123  // Get preview image
124  tr1::shared_ptr<QImage> previewImage = GetImage();
125 
126  // Update the image to reflect the correct pixel aspect ration (i.e. to fix non-squar pixels)
127  if (pixel_ratio.num != 1 || pixel_ratio.den != 1)
128  {
129  // Calculate correct DAR (display aspect ratio)
130  int new_width = previewImage->size().width();
131  int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
132 
133  // Resize to fix DAR
134  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
135  }
136 
137  // Create window
138  QWidget previewWindow;
139  previewWindow.setStyleSheet("background-color: #000000;");
140  QHBoxLayout layout;
141 
142  // Create label with current frame's image
143  QLabel previewLabel;
144  previewLabel.setPixmap(QPixmap::fromImage(*previewImage));
145  previewLabel.setMask(QPixmap::fromImage(*previewImage).mask());
146  layout.addWidget(&previewLabel);
147 
148  // Show the window
149  previewWindow.setLayout(&layout);
150  previewWindow.show();
151  previewApp->exec();
152 }
153 
154 // Get an audio waveform image
155 tr1::shared_ptr<QImage> Frame::GetWaveform(int width, int height, int Red, int Green, int Blue, int Alpha)
156 {
157  // Clear any existing waveform image
158  ClearWaveform();
159 
160  // Init a list of lines
161  QVector<QPointF> lines;
162  QVector<QPointF> labels;
163 
164  // Calculate width of an image based on the # of samples
165  int total_samples = audio->getNumSamples();
166  if (total_samples > 0)
167  {
168  // If samples are present...
169  int new_height = 200 * audio->getNumChannels();
170  int height_padding = 20 * (audio->getNumChannels() - 1);
171  int total_height = new_height + height_padding;
172  int total_width = 0;
173 
174  // Loop through each audio channel
175  int Y = 100;
176  for (int channel = 0; channel < audio->getNumChannels(); channel++)
177  {
178  int X = 0;
179 
180  // Get audio for this channel
181  const float *samples = audio->getReadPointer(channel);
182 
183  for (int sample = 0; sample < audio->getNumSamples(); sample++, X++)
184  {
185  // Sample value (scaled to -100 to 100)
186  float value = samples[sample] * 100;
187 
188  // Append a line segment for each sample
189  if (value != 0.0) {
190  // LINE
191  lines.push_back(QPointF(X,Y));
192  lines.push_back(QPointF(X,Y-value));
193  }
194  else {
195  // DOT
196  lines.push_back(QPointF(X,Y));
197  lines.push_back(QPointF(X,Y));
198  }
199  }
200 
201  // Add Channel Label Coordinate
202  labels.push_back(QPointF(5, Y - 5));
203 
204  // Increment Y
205  Y += (200 + height_padding);
206  total_width = X;
207  }
208 
209  // Create blank image
210  wave_image = tr1::shared_ptr<QImage>(new QImage(total_width, total_height, QImage::Format_RGBA8888));
211  wave_image->fill(QColor(0,0,0,0));
212 
213  // Load QPainter with wave_image device
214  QPainter painter(wave_image.get());
215 
216  // Set pen color
217  painter.setPen(QColor(Red, Green, Blue, Alpha));
218 
219  // Draw the waveform
220  painter.drawLines(lines);
221  painter.end();
222 
223  // Loop through the channels labels (and draw the text)
224  // TODO: Configure Fonts in Qt5 correctly, so the drawText method does not crash
225 // painter.setFont(QFont(QString("Arial"), 16, 1, false));
226 // for (int channel = 0; channel < labels.size(); channel++) {
227 // stringstream label;
228 // label << "Channel " << channel;
229 // painter.drawText(labels.at(channel), QString::fromStdString(label.str()));
230 // }
231 
232  // Resize Image (if requested)
233  if (width != total_width || height != total_height) {
234  QImage scaled_wave_image = wave_image->scaled(width, height, Qt::IgnoreAspectRatio, Qt::FastTransformation);
235  wave_image = tr1::shared_ptr<QImage>(new QImage(scaled_wave_image));
236  }
237  }
238  else
239  {
240  // No audio samples present
241  wave_image = tr1::shared_ptr<QImage>(new QImage(width, height, QImage::Format_RGBA8888));
242  wave_image->fill(QColor(QString::fromStdString("#000000")));
243  }
244 
245  // Return new image
246  return wave_image;
247 }
248 
249 // Clear the waveform image (and deallocate it's memory)
251 {
252  if (wave_image)
253  wave_image.reset();
254 }
255 
256 // Get an audio waveform image pixels
257 const unsigned char* Frame::GetWaveformPixels(int width, int height, int Red, int Green, int Blue, int Alpha)
258 {
259  // Get audio wave form image
260  wave_image = GetWaveform(width, height, Red, Green, Blue, Alpha);
261 
262  // Return array of pixel packets
263  return wave_image->bits();
264 }
265 
266 // Display the wave form
268 {
269  // Get audio wave form image
270  GetWaveform(720, 480, 0, 123, 255, 255);
271 
272  if (!QApplication::instance()) {
273  // Only create the QApplication once
274  static int argc = 1;
275  static char* argv[1] = {NULL};
276  previewApp = tr1::shared_ptr<QApplication>(new QApplication(argc, argv));
277  }
278 
279  // Create window
280  QWidget previewWindow;
281  previewWindow.setStyleSheet("background-color: #000000;");
282  QHBoxLayout layout;
283 
284  // Create label with current frame's waveform image
285  QLabel previewLabel;
286  previewLabel.setPixmap(QPixmap::fromImage(*wave_image));
287  previewLabel.setMask(QPixmap::fromImage(*wave_image).mask());
288  layout.addWidget(&previewLabel);
289 
290  // Show the window
291  previewWindow.setLayout(&layout);
292  previewWindow.show();
293  previewApp->exec();
294 
295  // Deallocate waveform image
296  ClearWaveform();
297 }
298 
299 // Get magnitude of range of samples (if channel is -1, return average of all channels for that sample)
300 float Frame::GetAudioSample(int channel, int sample, int magnitude_range)
301 {
302  if (channel > 0) {
303  // return average magnitude for a specific channel/sample range
304  return audio->getMagnitude(channel, sample, magnitude_range);
305 
306  } else {
307  // Return average magnitude for all channels
308  return audio->getMagnitude(sample, magnitude_range);
309  }
310 }
311 
312 // Get an array of sample data
313 float* Frame::GetAudioSamples(int channel)
314 {
315  // return JUCE audio data for this channel
316  return audio->getWritePointer(channel);
317 }
318 
319 // Get a planar array of sample data, using any sample rate
320 float* Frame::GetPlanarAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count)
321 {
322  float *output = NULL;
323  AudioSampleBuffer *buffer(audio.get());
324  int num_of_channels = audio->getNumChannels();
325  int num_of_samples = audio->getNumSamples();
326 
327  // Resample to new sample rate (if needed)
328  if (new_sample_rate != sample_rate)
329  {
330  // YES, RESAMPLE AUDIO
331  resampler->SetBuffer(audio.get(), sample_rate, new_sample_rate);
332 
333  // Resample data, and return new buffer pointer
334  buffer = resampler->GetResampledBuffer();
335 
336  // Update num_of_samples
337  num_of_samples = buffer->getNumSamples();
338  }
339 
340  // INTERLEAVE all samples together (channel 1 + channel 2 + channel 1 + channel 2, etc...)
341  output = new float[num_of_channels * num_of_samples];
342  int position = 0;
343 
344  // Loop through samples in each channel (combining them)
345  for (int channel = 0; channel < num_of_channels; channel++)
346  {
347  for (int sample = 0; sample < num_of_samples; sample++)
348  {
349  // Add sample to output array
350  output[position] = buffer->getReadPointer(channel)[sample];
351 
352  // increment position
353  position++;
354  }
355  }
356 
357  // Update sample count (since it might have changed due to resampling)
358  *sample_count = num_of_samples;
359 
360  // return combined array
361  return output;
362 }
363 
364 
365 // Get an array of sample data (all channels interleaved together), using any sample rate
366 float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count)
367 {
368  float *output = NULL;
369  AudioSampleBuffer *buffer(audio.get());
370  int num_of_channels = audio->getNumChannels();
371  int num_of_samples = audio->getNumSamples();
372 
373  // Resample to new sample rate (if needed)
374  if (new_sample_rate != sample_rate && resampler)
375  {
376  // YES, RESAMPLE AUDIO
377  resampler->SetBuffer(audio.get(), sample_rate, new_sample_rate);
378 
379  // Resample data, and return new buffer pointer
380  buffer = resampler->GetResampledBuffer();
381 
382  // Update num_of_samples
383  num_of_samples = buffer->getNumSamples();
384  }
385 
386  // INTERLEAVE all samples together (channel 1 + channel 2 + channel 1 + channel 2, etc...)
387  output = new float[num_of_channels * num_of_samples];
388  int position = 0;
389 
390  // Loop through samples in each channel (combining them)
391  for (int sample = 0; sample < num_of_samples; sample++)
392  {
393  for (int channel = 0; channel < num_of_channels; channel++)
394  {
395  // Add sample to output array
396  output[position] = buffer->getReadPointer(channel)[sample];
397 
398  // increment position
399  position++;
400  }
401  }
402 
403  // Update sample count (since it might have changed due to resampling)
404  *sample_count = num_of_samples;
405 
406  // return combined array
407  return output;
408 }
409 
410 // Get number of audio channels
412 {
413  return audio->getNumChannels();
414 }
415 
416 // Get number of audio samples
418 {
419  return audio->getNumSamples();
420 }
421 
422 juce::AudioSampleBuffer *Frame::GetAudioSampleBuffer()
423 {
424  return audio.get();
425 }
426 
427 // Get the size in bytes of this frame (rough estimate)
429 {
430  int64 total_bytes = 0;
431  if (image)
432  total_bytes += (width * height * sizeof(char) * 4);
433  if (audio) {
434  // approximate audio size (sample rate / 24 fps)
435  total_bytes += (sample_rate / 24.0) * sizeof(float);
436  }
437 
438  // return size of this frame
439  return total_bytes;
440 }
441 
442 // Get pixel data (as packets)
443 const unsigned char* Frame::GetPixels()
444 {
445  // Check for blank image
446  if (!image)
447  // Fill with black
448  AddColor(width, height, "#000000");
449 
450  // Return array of pixel packets
451  return image->bits();
452 }
453 
454 // Get pixel data (for only a single scan-line)
455 const unsigned char* Frame::GetPixels(int row)
456 {
457  // Return array of pixel packets
458  return image->scanLine(row);
459 }
460 
461 // Set Pixel Aspect Ratio
462 void Frame::SetPixelRatio(int num, int den)
463 {
464  pixel_ratio.num = num;
465  pixel_ratio.den = den;
466 }
467 
468 // Set frame number
469 void Frame::SetFrameNumber(int new_number)
470 {
471  number = new_number;
472 }
473 
474 // Calculate the # of samples per video frame (for a specific frame number and frame rate)
475 int Frame::GetSamplesPerFrame(long int number, Fraction fps, int sample_rate, int channels)
476 {
477  // Get the total # of samples for the previous frame, and the current frame (rounded)
478  double fps_rate = fps.Reciprocal().ToDouble();
479 
480  // Determine previous samples total, and make sure it's evenly divisible by the # of channels
481  double previous_samples = (sample_rate * fps_rate) * (number - 1);
482  double previous_samples_remainder = fmod(previous_samples, (double)channels); // subtract the remainder to the total (to make it evenly divisible)
483  previous_samples -= previous_samples_remainder;
484 
485  // Determine the current samples total, and make sure it's evenly divisible by the # of channels
486  double total_samples = (sample_rate * fps_rate) * number;
487  double total_samples_remainder = fmod(total_samples, (double)channels); // subtract the remainder to the total (to make it evenly divisible)
488  total_samples -= total_samples_remainder;
489 
490  // Subtract the previous frame's total samples with this frame's total samples. Not all sample rates can
491  // be evenly divided into frames, so each frame can have have different # of samples.
492  int samples_per_frame = round(total_samples - previous_samples);
493  return samples_per_frame;
494 }
495 
496 // Calculate the # of samples per video frame (for the current frame number)
497 int Frame::GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
498 {
499  return GetSamplesPerFrame(number, fps, sample_rate, channels);
500 }
501 
502 // Get height of image
504 {
505  return height;
506 }
507 
508 // Get height of image
510 {
511  return width;
512 }
513 
514 // Get the original sample rate of this frame's audio data
516 {
517  return sample_rate;
518 }
519 
520 // Get the original sample rate of this frame's audio data
522 {
523  return channel_layout;
524 }
525 
526 
527 // Save the frame image to the specified path. The image format is determined from the extension (i.e. image.PNG, image.JPEG)
528 void Frame::Save(string path, float scale, string format, int quality)
529 {
530  // Get preview image
531  tr1::shared_ptr<QImage> previewImage = GetImage();
532 
533  // scale image if needed
534  if (abs(scale) > 1.001 || abs(scale) < 0.999)
535  {
536  int new_width = width;
537  int new_height = height;
538 
539  // Update the image to reflect the correct pixel aspect ration (i.e. to fix non-squar pixels)
540  if (pixel_ratio.num != 1 || pixel_ratio.den != 1)
541  {
542  // Calculate correct DAR (display aspect ratio)
543  int new_width = previewImage->size().width();
544  int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
545 
546  // Resize to fix DAR
547  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
548  }
549 
550  // Resize image
551  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width * scale, new_height * scale, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
552  }
553 
554  // Save image
555  previewImage->save(QString::fromStdString(path), format.c_str(), quality);
556 }
557 
558 // Thumbnail the frame image to the specified path. The image format is determined from the extension (i.e. image.PNG, image.JPEG)
559 void Frame::Thumbnail(string path, int new_width, int new_height, string mask_path, string overlay_path,
560  string background_color, bool ignore_aspect, string format, int quality) throw(InvalidFile) {
561 
562  // Create blank thumbnail image & fill background color
563  tr1::shared_ptr<QImage> thumbnail = tr1::shared_ptr<QImage>(new QImage(new_width, new_height, QImage::Format_RGBA8888));
564  thumbnail->fill(QColor(QString::fromStdString(background_color)));
565 
566  // Create transform and painter
567  QTransform transform;
568  QPainter painter(thumbnail.get());
569  painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, true);
570 
571 
572  // Get preview image
573  tr1::shared_ptr<QImage> previewImage = GetImage();
574 
575  // Update the image to reflect the correct pixel aspect ration (i.e. to fix non-squar pixels)
576  if (pixel_ratio.num != 1 || pixel_ratio.den != 1)
577  {
578  // Calculate correct DAR (display aspect ratio)
579  int aspect_width = previewImage->size().width();
580  int aspect_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
581 
582  // Resize to fix DAR
583  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(aspect_width, aspect_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
584  }
585 
586  // Resize frame image
587  if (ignore_aspect)
588  // Ignore aspect ratio
589  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
590  else
591  // Maintain aspect ratio
592  previewImage = tr1::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
593 
594  // Composite frame image onto background (centered)
595  int x = (new_width - previewImage->size().width()) / 2.0; // center
596  int y = (new_height - previewImage->size().height()) / 2.0; // center
597  painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
598  painter.drawImage(x, y, *previewImage);
599 
600 
601  // Overlay Image (if any)
602  if (overlay_path != "") {
603  // Open overlay
604  tr1::shared_ptr<QImage> overlay = tr1::shared_ptr<QImage>(new QImage());
605  overlay->load(QString::fromStdString(overlay_path));
606 
607  // Set pixel format
608  overlay = tr1::shared_ptr<QImage>(new QImage(overlay->convertToFormat(QImage::Format_RGBA8888)));
609 
610  // Resize to fit
611  overlay = tr1::shared_ptr<QImage>(new QImage(overlay->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
612 
613  // Composite onto thumbnail
614  painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
615  painter.drawImage(0, 0, *overlay);
616  }
617 
618 
619  // Mask Image (if any)
620  if (mask_path != "") {
621  // Open mask
622  tr1::shared_ptr<QImage> mask = tr1::shared_ptr<QImage>(new QImage());
623  mask->load(QString::fromStdString(mask_path));
624 
625  // Set pixel format
626  mask = tr1::shared_ptr<QImage>(new QImage(mask->convertToFormat(QImage::Format_RGBA8888)));
627 
628  // Resize to fit
629  mask = tr1::shared_ptr<QImage>(new QImage(mask->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
630 
631  // Negate mask
632  mask->invertPixels();
633 
634  // Get pixels
635  unsigned char *pixels = (unsigned char *) thumbnail->bits();
636  unsigned char *mask_pixels = (unsigned char *) mask->bits();
637 
638  // Convert the mask image to grayscale
639  // Loop through pixels
640  for (int pixel = 0, byte_index=0; pixel < new_width * new_height; pixel++, byte_index+=4)
641  {
642  // Get the RGB values from the pixel
643  int gray_value = qGray(mask_pixels[byte_index], mask_pixels[byte_index] + 1, mask_pixels[byte_index] + 2);
644  int Frame_Alpha = pixels[byte_index + 3];
645  int Mask_Value = constrain(Frame_Alpha - gray_value);
646 
647  // Set all alpha pixels to gray value
648  pixels[byte_index + 3] = Mask_Value;
649  }
650  }
651 
652 
653  // End painter
654  painter.end();
655 
656  // Save image
657  thumbnail->save(QString::fromStdString(path), format.c_str(), quality);
658 }
659 
660 // Constrain a color value from 0 to 255
661 int Frame::constrain(int color_value)
662 {
663  // Constrain new color from 0 to 255
664  if (color_value < 0)
665  color_value = 0;
666  else if (color_value > 255)
667  color_value = 255;
668 
669  return color_value;
670 }
671 
672 // Add (or replace) pixel data to the frame (based on a solid color)
673 void Frame::AddColor(int new_width, int new_height, string color)
674 {
675  // Create new image object, and fill with pixel data
676  const GenericScopedLock<CriticalSection> lock(addingImageSection);
677  image = tr1::shared_ptr<QImage>(new QImage(new_width, new_height, QImage::Format_RGBA8888));
678 
679  // Fill with solid color
680  image->fill(QColor(QString::fromStdString(color)));
681 
682  // Update height and width
683  width = image->width();
684  height = image->height();
685  has_image_data = true;
686 }
687 
688 // Add (or replace) pixel data to the frame
689 void Frame::AddImage(int new_width, int new_height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_)
690 {
691  // Create new buffer
692  const GenericScopedLock<CriticalSection> lock(addingImageSection);
693  int buffer_size = new_width * new_height * bytes_per_pixel;
694  qbuffer = new unsigned char[buffer_size]();
695 
696  // Copy buffer data
697  memcpy((unsigned char*)qbuffer, pixels_, buffer_size);
698 
699  // Create new image object, and fill with pixel data
700  image = tr1::shared_ptr<QImage>(new QImage(qbuffer, new_width, new_height, new_width * bytes_per_pixel, type, (QImageCleanupFunction) &openshot::Frame::cleanUpBuffer, (void*) qbuffer));
701 
702  // Always convert to RGBA8888 (if different)
703  if (image->format() != QImage::Format_RGBA8888)
704  image->convertToFormat(QImage::Format_RGBA8888);
705 
706  // Update height and width
707  width = image->width();
708  height = image->height();
709  has_image_data = true;
710 }
711 
712 // Add (or replace) pixel data to the frame
713 void Frame::AddImage(tr1::shared_ptr<QImage> new_image)
714 {
715  // Ignore blank images
716  if (!new_image)
717  return;
718 
719  // assign image data
720  const GenericScopedLock<CriticalSection> lock(addingImageSection);
721  image = new_image;
722 
723  // Always convert to RGBA8888 (if different)
724  if (image->format() != QImage::Format_RGBA8888)
725  image->convertToFormat(QImage::Format_RGBA8888);
726 
727  // Update height and width
728  width = image->width();
729  height = image->height();
730  has_image_data = true;
731 }
732 
733 // Add (or replace) pixel data to the frame (for only the odd or even lines)
734 void Frame::AddImage(tr1::shared_ptr<QImage> new_image, bool only_odd_lines)
735 {
736  // Ignore blank new_image
737  if (!new_image)
738  return;
739 
740  // Check for blank source image
741  if (!image) {
742  // Replace the blank source image
743  AddImage(new_image);
744 
745  } else {
746 
747  // Ignore image of different sizes or formats
748  if (image == new_image || image->size() != image->size() || image->format() != image->format())
749  return;
750 
751  // Get the frame's image
752  const GenericScopedLock<CriticalSection> lock(addingImageSection);
753  const unsigned char *pixels = image->bits();
754  const unsigned char *new_pixels = new_image->bits();
755 
756  // Loop through the scanlines of the image (even or odd)
757  int start = 0;
758  if (only_odd_lines)
759  start = 1;
760  for (int row = start; row < image->height(); row += 2) {
761  memcpy((unsigned char *) pixels, new_pixels + (row * image->bytesPerLine()), image->bytesPerLine());
762  new_pixels += image->bytesPerLine();
763  }
764 
765  // Update height and width
766  width = image->width();
767  height = image->height();
768  has_image_data = true;
769  }
770 }
771 
772 
773 // Resize audio container to hold more (or less) samples and channels
774 void Frame::ResizeAudio(int channels, int length, int rate, ChannelLayout layout)
775 {
776  // Resize JUCE audio buffer
777  audio->setSize(channels, length, true, true, false);
778  channel_layout = layout;
779  sample_rate = rate;
780 }
781 
782 // Add audio samples to a specific channel
783 void Frame::AddAudio(bool replaceSamples, int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f)
784 {
785  // Extend audio container to hold more (or less) samples and channels.. if needed
786  int new_length = destStartSample + numSamples;
787  int new_channel_length = audio->getNumChannels();
788  if (destChannel >= new_channel_length)
789  new_channel_length = destChannel + 1;
790  if (new_length > audio->getNumSamples() || new_channel_length > audio->getNumChannels())
791  audio->setSize(new_channel_length, new_length, true, true, false);
792 
793  // Clear the range of samples first (if needed)
794  if (replaceSamples)
795  audio->clear(destChannel, destStartSample, numSamples);
796 
797  // Add samples to frame's audio buffer
798  audio->addFrom(destChannel, destStartSample, source, numSamples, gainToApplyToSource);
799  has_audio_data = true;
800 }
801 
802 // Apply gain ramp (i.e. fading volume)
803 void Frame::ApplyGainRamp(int destChannel, int destStartSample, int numSamples, float initial_gain = 0.0f, float final_gain = 1.0f)
804 {
805  // Apply gain ramp
806  audio->applyGainRamp(destChannel, destStartSample, numSamples, initial_gain, final_gain);
807 }
808 
809 // Get pointer to Magick++ image object
810 tr1::shared_ptr<QImage> Frame::GetImage()
811 {
812  // Check for blank image
813  if (!image)
814  // Fill with black
815  AddColor(width, height, "#000000");
816 
817  return image;
818 }
819 
820 #ifdef USE_IMAGEMAGICK
821 // Get pointer to ImageMagick image object
822 tr1::shared_ptr<Magick::Image> Frame::GetMagickImage()
823 {
824  // Check for blank image
825  if (!image)
826  // Fill with black
827  AddColor(width, height, "#000000");
828 
829  // Get the pixels from the frame image
830  QRgb const *tmpBits = (const QRgb*)image->bits();
831 
832  // Create new image object, and fill with pixel data
833  tr1::shared_ptr<Magick::Image> magick_image = tr1::shared_ptr<Magick::Image>(new Magick::Image(image->width(), image->height(),"RGBA", Magick::CharPixel, tmpBits));
834 
835  // Give image a transparent background color
836  magick_image->backgroundColor(Magick::Color("none"));
837  magick_image->virtualPixelMethod(Magick::TransparentVirtualPixelMethod);
838  magick_image->matte(true);
839 
840  return magick_image;
841 }
842 #endif
843 
844 #ifdef USE_IMAGEMAGICK
845 // Get pointer to QImage of frame
846 void Frame::AddMagickImage(tr1::shared_ptr<Magick::Image> new_image)
847 {
848  const int BPP = 4;
849  const std::size_t bufferSize = new_image->columns() * new_image->rows() * BPP;
850 
851  /// Use realloc for fast memory allocation.
852  /// TODO: consider locking the buffer for mt safety
853  //qbuffer = reinterpret_cast<unsigned char*>(realloc(qbuffer, bufferSize));
854  qbuffer = new unsigned char[bufferSize]();
855  unsigned char *buffer = (unsigned char*)qbuffer;
856 
857  // Iterate through the pixel packets, and load our own buffer
858  // Each color needs to be scaled to 8 bit (using the ImageMagick built-in ScaleQuantumToChar function)
859  int numcopied = 0;
860  Magick::PixelPacket *pixels = new_image->getPixels(0,0, new_image->columns(), new_image->rows());
861  for (int n = 0, i = 0; n < new_image->columns() * new_image->rows(); n += 1, i += 4) {
862  buffer[i+0] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].red);
863  buffer[i+1] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].green);
864  buffer[i+2] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].blue);
865  buffer[i+3] = 255 - MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].opacity);
866  numcopied+=4;
867  }
868 
869  // Create QImage of frame data
870  image = tr1::shared_ptr<QImage>(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer));
871 
872  // Update height and width
873  width = image->width();
874  height = image->height();
875  has_image_data = true;
876 }
877 #endif
878 
879 // Play audio samples for this frame
881 {
882  // Check if samples are present
883  if (!audio->getNumSamples())
884  return;
885 
886  AudioDeviceManager deviceManager;
887  deviceManager.initialise (0, /* number of input channels */
888  2, /* number of output channels */
889  0, /* no XML settings.. */
890  true /* select default device on failure */);
891  //deviceManager.playTestSound();
892 
893  AudioSourcePlayer audioSourcePlayer;
894  deviceManager.addAudioCallback (&audioSourcePlayer);
895 
896  ScopedPointer<AudioBufferSource> my_source;
897  my_source = new AudioBufferSource(audio.get());
898 
899  // Create TimeSliceThread for audio buffering
900  TimeSliceThread my_thread("Audio buffer thread");
901 
902  // Start thread
903  my_thread.startThread();
904 
905  AudioTransportSource transport1;
906  transport1.setSource (my_source,
907  5000, // tells it to buffer this many samples ahead
908  &my_thread,
909  (double) sample_rate,
910  audio->getNumChannels()); // sample rate of source
911  transport1.setPosition (0);
912  transport1.setGain(1.0);
913 
914 
915  // Create MIXER
916  MixerAudioSource mixer;
917  mixer.addInputSource(&transport1, false);
918  audioSourcePlayer.setSource (&mixer);
919 
920  // Start transports
921  transport1.start();
922 
923  while (transport1.isPlaying())
924  {
925  cout << "playing" << endl;
926  usleep(1000000);
927  }
928 
929  cout << "DONE!!!" << endl;
930 
931  transport1.stop();
932  transport1.setSource (0);
933  audioSourcePlayer.setSource (0);
934  my_thread.stopThread(500);
935  deviceManager.removeAudioCallback (&audioSourcePlayer);
936  deviceManager.closeAudioDevice();
937  deviceManager.removeAllChangeListeners();
938  deviceManager.dispatchPendingMessages();
939 
940  cout << "End of Play()" << endl;
941 
942 
943 }
944 
945 // Clean up buffer after QImage is deleted
946 void Frame::cleanUpBuffer(void *info)
947 {
948  if (info)
949  {
950  // Remove buffer since QImage tells us to
951  unsigned char* ptr_to_qbuffer = (unsigned char*) info;
952  delete[] ptr_to_qbuffer;
953  }
954 }
955 
956 // Add audio silence
957 void Frame::AddAudioSilence(int numSamples)
958 {
959  // Resize audio container
960  audio->setSize(channels, numSamples, false, true, false);
961  audio->clear();
962  has_audio_data = true;
963 }
void Thumbnail(string path, int new_width, int new_height, string mask_path, string overlay_path, string background_color, bool ignore_aspect, string format="png", int quality=100)
Definition: Frame.cpp:559
void SetBuffer(AudioSampleBuffer *new_buffer, double sample_rate, double new_sample_rate)
Sets the audio buffer and key settings.
int GetWidth()
Get height of image.
Definition: Frame.cpp:509
int num
Numerator for the fraction.
Definition: Fraction.h:44
int GetAudioSamplesCount()
Get number of audio samples.
Definition: Frame.cpp:417
void AddColor(int new_width, int new_height, string color)
Add (or replace) pixel data to the frame (based on a solid color)
Definition: Frame.cpp:673
float * GetInterleavedAudioSamples(int new_sample_rate, AudioResampler *resampler, int *sample_count)
Get an array of sample data (all channels interleaved together), using any sample rate...
Definition: Frame.cpp:366
tr1::shared_ptr< QImage > GetImage()
Get pointer to Qt QImage image object.
Definition: Frame.cpp:810
This class represents a single frame of video (i.e. image & audio data)
Definition: Frame.h:115
const unsigned char * GetWaveformPixels(int width, int height, int Red, int Green, int Blue, int Alpha)
Get an audio waveform image pixels.
Definition: Frame.cpp:257
juce::AudioSampleBuffer * GetAudioSampleBuffer()
Definition: Frame.cpp:422
const unsigned char * GetPixels()
Get pixel data (as packets)
Definition: Frame.cpp:443
void Play()
Play audio samples for this frame.
Definition: Frame.cpp:880
void Save(string path, float scale, string format="PNG", int quality=100)
Save the frame image to the specified path. The image format can be BMP, JPG, JPEG, PNG, PPM, XBM, XPM.
Definition: Frame.cpp:528
long int number
This is the frame number (starting at 1)
Definition: Frame.h:135
void DeepCopy(const Frame &other)
Copy data and pointers from another Frame instance.
Definition: Frame.cpp:89
void AddAudio(bool replaceSamples, int destChannel, int destStartSample, const float *source, int numSamples, float gainToApplyToSource)
Add audio samples to a specific channel.
Definition: Frame.cpp:783
void Display()
Display the frame image to the screen (primarily used for debugging reasons)
Definition: Frame.cpp:114
Fraction Reciprocal()
Return the reciprocal as a Fraction.
Definition: Fraction.cpp:81
This class is used to expose an AudioSampleBuffer as an AudioSource in JUCE.
void ClearWaveform()
Clear the waveform image (and deallocate it&#39;s memory)
Definition: Frame.cpp:250
float * GetAudioSamples(int channel)
Get an array of sample data.
Definition: Frame.cpp:313
Exception for files that can not be found or opened.
Definition: Exceptions.h:132
void AddAudioSilence(int numSamples)
Add audio silence.
Definition: Frame.cpp:957
bool has_audio_data
This frame has been loaded with audio data.
Definition: Frame.h:136
This class represents a fraction.
Definition: Fraction.h:42
static void cleanUpBuffer(void *info)
Clean up buffer after QImage is deleted.
Definition: Frame.cpp:946
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround...
tr1::shared_ptr< QImage > GetWaveform(int width, int height, int Red, int Green, int Blue, int Alpha)
Get an audio waveform image.
Definition: Frame.cpp:155
void AddImage(int new_width, int new_height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_)
Add (or replace) pixel data to the frame.
Definition: Frame.cpp:689
Frame()
Constructor - blank frame (300x200 blank image, 48kHz audio silence)
Definition: Frame.cpp:34
void ApplyGainRamp(int destChannel, int destStartSample, int numSamples, float initial_gain, float final_gain)
Apply gain ramp (i.e. fading volume)
Definition: Frame.cpp:803
void DisplayWaveform()
Display the wave form.
Definition: Frame.cpp:267
void SetPixelRatio(int num, int den)
Set Pixel Aspect Ratio.
Definition: Frame.cpp:462
int GetAudioChannelsCount()
Get number of audio channels.
Definition: Frame.cpp:411
This namespace is the default namespace for all code in the openshot library.
ChannelLayout ChannelsLayout()
Definition: Frame.cpp:521
~Frame()
Assignment operator.
Definition: Frame.cpp:107
int64 GetBytes()
Get the size in bytes of this frame (rough estimate)
Definition: Frame.cpp:428
AudioSampleBuffer * GetResampledBuffer()
Get the resampled audio buffer.
float * GetPlanarAudioSamples(int new_sample_rate, AudioResampler *resampler, int *sample_count)
Definition: Frame.cpp:320
int den
Denominator for the fraction.
Definition: Fraction.h:45
float GetAudioSample(int channel, int sample, int magnitude_range)
Get magnitude of range of samples (if channel is -1, return average of all channels for that sample) ...
Definition: Frame.cpp:300
void SetFrameNumber(int number)
Set frame number.
Definition: Frame.cpp:469
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:497
bool has_image_data
This frame has been loaded with pixel data.
Definition: Frame.h:137
void ResizeAudio(int channels, int length, int sample_rate, ChannelLayout channel_layout)
Resize audio container to hold more (or less) samples and channels.
Definition: Frame.cpp:774
int GetHeight()
Get height of image.
Definition: Frame.cpp:503
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:46
int SampleRate()
Get the original sample rate of this frame&#39;s audio data.
Definition: Frame.cpp:515
This class is used to resample audio data for many sequential frames.