28 #include "../include/Frame.h" 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)
38 audio = tr1::shared_ptr<juce::AudioSampleBuffer>(
new juce::AudioSampleBuffer(channels, 0));
46 : number(number), pixel_ratio(1,1), channels(2), width(width), height(height),
50 audio = tr1::shared_ptr<juce::AudioSampleBuffer>(
new juce::AudioSampleBuffer(channels, 0));
58 number(number), pixel_ratio(1,1), channels(channels), width(1), height(1),
62 audio = tr1::shared_ptr<juce::AudioSampleBuffer>(
new juce::AudioSampleBuffer(channels, samples));
70 : number(number), pixel_ratio(1,1), channels(channels), width(width), height(height),
74 audio = tr1::shared_ptr<juce::AudioSampleBuffer>(
new juce::AudioSampleBuffer(channels, samples));
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;
102 if (other.wave_image)
103 wave_image = tr1::shared_ptr<QImage>(
new QImage(*(other.wave_image)));
116 if (!QApplication::instance()) {
119 static char* argv[1] = {NULL};
120 previewApp = tr1::shared_ptr<QApplication>(
new QApplication(argc, argv));
124 tr1::shared_ptr<QImage> previewImage =
GetImage();
127 if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
130 int new_width = previewImage->size().width();
134 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
138 QWidget previewWindow;
139 previewWindow.setStyleSheet(
"background-color: #000000;");
144 previewLabel.setPixmap(QPixmap::fromImage(*previewImage));
145 previewLabel.setMask(QPixmap::fromImage(*previewImage).mask());
146 layout.addWidget(&previewLabel);
149 previewWindow.setLayout(&layout);
150 previewWindow.show();
155 tr1::shared_ptr<QImage>
Frame::GetWaveform(
int width,
int height,
int Red,
int Green,
int Blue,
int Alpha)
161 QVector<QPointF> lines;
162 QVector<QPointF> labels;
165 int total_samples = audio->getNumSamples();
166 if (total_samples > 0)
169 int new_height = 200 * audio->getNumChannels();
170 int height_padding = 20 * (audio->getNumChannels() - 1);
171 int total_height = new_height + height_padding;
176 for (
int channel = 0; channel < audio->getNumChannels(); channel++)
181 const float *samples = audio->getReadPointer(channel);
183 for (
int sample = 0; sample < audio->getNumSamples(); sample++, X++)
186 float value = samples[sample] * 100;
191 lines.push_back(QPointF(X,Y));
192 lines.push_back(QPointF(X,Y-value));
196 lines.push_back(QPointF(X,Y));
197 lines.push_back(QPointF(X,Y));
202 labels.push_back(QPointF(5, Y - 5));
205 Y += (200 + height_padding);
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));
214 QPainter painter(wave_image.get());
217 painter.setPen(QColor(Red, Green, Blue, Alpha));
220 painter.drawLines(lines);
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));
241 wave_image = tr1::shared_ptr<QImage>(
new QImage(width, height, QImage::Format_RGBA8888));
242 wave_image->fill(QColor(QString::fromStdString(
"#000000")));
260 wave_image =
GetWaveform(width, height, Red, Green, Blue, Alpha);
263 return wave_image->bits();
272 if (!QApplication::instance()) {
275 static char* argv[1] = {NULL};
276 previewApp = tr1::shared_ptr<QApplication>(
new QApplication(argc, argv));
280 QWidget previewWindow;
281 previewWindow.setStyleSheet(
"background-color: #000000;");
286 previewLabel.setPixmap(QPixmap::fromImage(*wave_image));
287 previewLabel.setMask(QPixmap::fromImage(*wave_image).mask());
288 layout.addWidget(&previewLabel);
291 previewWindow.setLayout(&layout);
292 previewWindow.show();
304 return audio->getMagnitude(channel, sample, magnitude_range);
308 return audio->getMagnitude(sample, magnitude_range);
316 return audio->getWritePointer(channel);
322 float *output = NULL;
323 AudioSampleBuffer *buffer(audio.get());
324 int num_of_channels = audio->getNumChannels();
325 int num_of_samples = audio->getNumSamples();
328 if (new_sample_rate != sample_rate)
331 resampler->
SetBuffer(audio.get(), sample_rate, new_sample_rate);
337 num_of_samples = buffer->getNumSamples();
341 output =
new float[num_of_channels * num_of_samples];
345 for (
int channel = 0; channel < num_of_channels; channel++)
347 for (
int sample = 0; sample < num_of_samples; sample++)
350 output[position] = buffer->getReadPointer(channel)[sample];
358 *sample_count = num_of_samples;
368 float *output = NULL;
369 AudioSampleBuffer *buffer(audio.get());
370 int num_of_channels = audio->getNumChannels();
371 int num_of_samples = audio->getNumSamples();
374 if (new_sample_rate != sample_rate && resampler)
377 resampler->
SetBuffer(audio.get(), sample_rate, new_sample_rate);
383 num_of_samples = buffer->getNumSamples();
387 output =
new float[num_of_channels * num_of_samples];
391 for (
int sample = 0; sample < num_of_samples; sample++)
393 for (
int channel = 0; channel < num_of_channels; channel++)
396 output[position] = buffer->getReadPointer(channel)[sample];
404 *sample_count = num_of_samples;
413 return audio->getNumChannels();
419 return audio->getNumSamples();
430 int64 total_bytes = 0;
432 total_bytes += (width * height *
sizeof(char) * 4);
435 total_bytes += (sample_rate / 24.0) *
sizeof(float);
451 return image->bits();
458 return image->scanLine(row);
464 pixel_ratio.
num = num;
465 pixel_ratio.
den = den;
481 double previous_samples = (sample_rate * fps_rate) * (number - 1);
482 double previous_samples_remainder = fmod(previous_samples, (
double)channels);
483 previous_samples -= previous_samples_remainder;
486 double total_samples = (sample_rate * fps_rate) * number;
487 double total_samples_remainder = fmod(total_samples, (
double)channels);
488 total_samples -= total_samples_remainder;
492 int samples_per_frame = round(total_samples - previous_samples);
493 return samples_per_frame;
523 return channel_layout;
528 void Frame::Save(
string path,
float scale,
string format,
int quality)
531 tr1::shared_ptr<QImage> previewImage =
GetImage();
534 if (abs(scale) > 1.001 || abs(scale) < 0.999)
536 int new_width = width;
537 int new_height = height;
540 if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
543 int new_width = previewImage->size().width();
547 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
551 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(new_width * scale, new_height * scale, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
555 previewImage->save(QString::fromStdString(path), format.c_str(), quality);
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) {
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)));
567 QTransform transform;
568 QPainter painter(thumbnail.get());
569 painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing,
true);
573 tr1::shared_ptr<QImage> previewImage =
GetImage();
576 if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
579 int aspect_width = previewImage->size().width();
580 int aspect_height = previewImage->size().height() * pixel_ratio.
Reciprocal().
ToDouble();
583 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(aspect_width, aspect_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
589 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
592 previewImage = tr1::shared_ptr<QImage>(
new QImage(previewImage->scaled(new_width, new_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
595 int x = (new_width - previewImage->size().width()) / 2.0;
596 int y = (new_height - previewImage->size().height()) / 2.0;
597 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
598 painter.drawImage(x, y, *previewImage);
602 if (overlay_path !=
"") {
604 tr1::shared_ptr<QImage> overlay = tr1::shared_ptr<QImage>(
new QImage());
605 overlay->load(QString::fromStdString(overlay_path));
608 overlay = tr1::shared_ptr<QImage>(
new QImage(overlay->convertToFormat(QImage::Format_RGBA8888)));
611 overlay = tr1::shared_ptr<QImage>(
new QImage(overlay->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
614 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
615 painter.drawImage(0, 0, *overlay);
620 if (mask_path !=
"") {
622 tr1::shared_ptr<QImage> mask = tr1::shared_ptr<QImage>(
new QImage());
623 mask->load(QString::fromStdString(mask_path));
626 mask = tr1::shared_ptr<QImage>(
new QImage(mask->convertToFormat(QImage::Format_RGBA8888)));
629 mask = tr1::shared_ptr<QImage>(
new QImage(mask->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
632 mask->invertPixels();
635 unsigned char *pixels = (
unsigned char *) thumbnail->bits();
636 unsigned char *mask_pixels = (
unsigned char *) mask->bits();
640 for (
int pixel = 0, byte_index=0; pixel < new_width * new_height; pixel++, byte_index+=4)
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);
648 pixels[byte_index + 3] = Mask_Value;
657 thumbnail->save(QString::fromStdString(path), format.c_str(), quality);
661 int Frame::constrain(
int color_value)
666 else if (color_value > 255)
676 const GenericScopedLock<CriticalSection> lock(addingImageSection);
677 image = tr1::shared_ptr<QImage>(
new QImage(width, height, QImage::Format_RGBA8888));
680 image->fill(QColor(QString::fromStdString(color)));
683 width = image->width();
684 height = image->height();
689 void Frame::AddImage(
int width,
int height,
int bytes_per_pixel, QImage::Format type,
const unsigned char *pixels_)
692 const GenericScopedLock<CriticalSection> lock(addingImageSection);
693 int buffer_size = width * height * bytes_per_pixel;
694 qbuffer =
new unsigned char[buffer_size]();
697 memcpy((
unsigned char*)qbuffer, pixels_, buffer_size);
700 image = tr1::shared_ptr<QImage>(
new QImage(qbuffer, width, height, width * bytes_per_pixel, type, (QImageCleanupFunction) &
openshot::Frame::cleanUpBuffer, (
void*) qbuffer));
703 if (image->format() != QImage::Format_RGBA8888)
704 image->convertToFormat(QImage::Format_RGBA8888);
707 width = image->width();
708 height = image->height();
720 const GenericScopedLock<CriticalSection> lock(addingImageSection);
724 if (image->format() != QImage::Format_RGBA8888)
725 image->convertToFormat(QImage::Format_RGBA8888);
728 width = image->width();
729 height = image->height();
748 if (image == new_image || image->size() != image->size() || image->format() != image->format())
752 const GenericScopedLock<CriticalSection> lock(addingImageSection);
753 const unsigned char *pixels = image->bits();
754 const unsigned char *new_pixels = new_image->bits();
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();
766 width = image->width();
767 height = image->height();
777 audio->setSize(channels, length,
true,
true,
false);
778 channel_layout = layout;
783 void Frame::AddAudio(
bool replaceSamples,
int destChannel,
int destStartSample,
const float* source,
int numSamples,
float gainToApplyToSource = 1.0f)
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);
795 audio->clear(destChannel, destStartSample, numSamples);
798 audio->addFrom(destChannel, destStartSample, source, numSamples, gainToApplyToSource);
803 void Frame::ApplyGainRamp(
int destChannel,
int destStartSample,
int numSamples,
float initial_gain = 0.0f,
float final_gain = 1.0f)
806 audio->applyGainRamp(destChannel, destStartSample, numSamples, initial_gain, final_gain);
820 #ifdef USE_IMAGEMAGICK 822 tr1::shared_ptr<Magick::Image> Frame::GetMagickImage()
830 QRgb
const *tmpBits = (
const QRgb*)image->bits();
833 tr1::shared_ptr<Magick::Image> magick_image = tr1::shared_ptr<Magick::Image>(
new Magick::Image(image->width(), image->height(),
"RGBA", Magick::CharPixel, tmpBits));
836 magick_image->backgroundColor(Magick::Color(
"none"));
837 magick_image->virtualPixelMethod(Magick::TransparentVirtualPixelMethod);
838 magick_image->matte(
true);
844 #ifdef USE_IMAGEMAGICK 846 void Frame::AddMagickImage(tr1::shared_ptr<Magick::Image> new_image)
849 const std::size_t bufferSize = new_image->columns() * new_image->rows() * BPP;
854 qbuffer =
new unsigned char[bufferSize]();
855 unsigned char *buffer = (
unsigned char*)qbuffer;
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);
870 image = tr1::shared_ptr<QImage>(
new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &
cleanUpBuffer, (
void*) qbuffer));
873 width = image->width();
874 height = image->height();
883 if (!audio->getNumSamples())
886 AudioDeviceManager deviceManager;
887 deviceManager.initialise (0,
893 AudioSourcePlayer audioSourcePlayer;
894 deviceManager.addAudioCallback (&audioSourcePlayer);
896 ScopedPointer<AudioBufferSource> my_source;
900 TimeSliceThread my_thread(
"Audio buffer thread");
903 my_thread.startThread();
905 AudioTransportSource transport1;
906 transport1.setSource (my_source,
909 (
double) sample_rate,
910 audio->getNumChannels());
911 transport1.setPosition (0);
912 transport1.setGain(1.0);
916 MixerAudioSource mixer;
917 mixer.addInputSource(&transport1,
false);
918 audioSourcePlayer.setSource (&mixer);
923 while (transport1.isPlaying())
925 cout <<
"playing" << endl;
929 cout <<
"DONE!!!" << endl;
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();
940 cout <<
"End of Play()" << endl;
951 unsigned char* ptr_to_qbuffer = (
unsigned char*) info;
952 delete[] ptr_to_qbuffer;
960 audio->setSize(channels, numSamples,
false,
true,
false);
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)
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.
int num
Numerator for the fraction.
int GetAudioSamplesCount()
Get number of audio samples.
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...
tr1::shared_ptr< QImage > GetImage()
Get pointer to Qt QImage image object.
This class represents a single frame of video (i.e. image & audio data)
const unsigned char * GetWaveformPixels(int width, int height, int Red, int Green, int Blue, int Alpha)
Get an audio waveform image pixels.
juce::AudioSampleBuffer * GetAudioSampleBuffer()
const unsigned char * GetPixels()
Get pixel data (as packets)
void Play()
Play audio samples for this frame.
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.
long int number
This is the frame number (starting at 1)
void AddImage(int width, int height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_)
Add (or replace) pixel data to the frame.
void DeepCopy(const Frame &other)
Copy data and pointers from another Frame instance.
void AddAudio(bool replaceSamples, int destChannel, int destStartSample, const float *source, int numSamples, float gainToApplyToSource)
Add audio samples to a specific channel.
void Display()
Display the frame image to the screen (primarily used for debugging reasons)
Fraction Reciprocal()
Return the reciprocal as a Fraction.
void AddColor(int width, int height, string color)
Add (or replace) pixel data to the frame (based on a solid color)
This class is used to expose an AudioSampleBuffer as an AudioSource in JUCE.
void ClearWaveform()
Clear the waveform image (and deallocate it's memory)
float * GetAudioSamples(int channel)
Get an array of sample data.
Exception for files that can not be found or opened.
void AddAudioSilence(int numSamples)
Add audio silence.
bool has_audio_data
This frame has been loaded with audio data.
This class represents a fraction.
static void cleanUpBuffer(void *info)
Clean up buffer after QImage is deleted.
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.
Frame()
Constructor - blank frame (300x200 blank image, 48kHz audio silence)
void ApplyGainRamp(int destChannel, int destStartSample, int numSamples, float initial_gain, float final_gain)
Apply gain ramp (i.e. fading volume)
void DisplayWaveform()
Display the wave form.
void SetPixelRatio(int num, int den)
Set Pixel Aspect Ratio.
int GetAudioChannelsCount()
Get number of audio channels.
This namespace is the default namespace for all code in the openshot library.
ChannelLayout ChannelsLayout()
~Frame()
Assignment operator.
int64 GetBytes()
Get the size in bytes of this frame (rough estimate)
AudioSampleBuffer * GetResampledBuffer()
Get the resampled audio buffer.
float * GetPlanarAudioSamples(int new_sample_rate, AudioResampler *resampler, int *sample_count)
int den
Denominator for the fraction.
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) ...
void SetFrameNumber(int number)
Set frame number.
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
bool has_image_data
This frame has been loaded with pixel data.
void ResizeAudio(int channels, int length, int sample_rate, ChannelLayout channel_layout)
Resize audio container to hold more (or less) samples and channels.
int GetHeight()
Get height of image.
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
int SampleRate()
Get the original sample rate of this frame's audio data.
This class is used to resample audio data for many sequential frames.