You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Merge branch 'develop' into develop
This commit is contained in:
@@ -75,6 +75,13 @@ Generating build files for OpenShot
|
||||
SO/API/ABI Version: ${SO_VERSION}
|
||||
")
|
||||
|
||||
#### Work around a GCC < 9 bug with handling of _Pragma() in macros
|
||||
#### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
|
||||
if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND
|
||||
(${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS "9.0.0"))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-integrated-cpp")
|
||||
endif()
|
||||
|
||||
#### Enable C++11 (for std::shared_ptr support)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace openshot {
|
||||
/// @param max_bytes The maximum bytes to allow in the cache. Once exceeded, the cache will purge the oldest frames.
|
||||
CacheBase(int64_t max_bytes);
|
||||
|
||||
virtual ~CacheBase();
|
||||
|
||||
/// @brief Add a Frame to the cache
|
||||
/// @param frame The openshot::Frame object needing to be cached.
|
||||
virtual void Add(std::shared_ptr<Frame> frame) = 0;
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace openshot {
|
||||
CacheMemory(int64_t max_bytes);
|
||||
|
||||
// Default destructor
|
||||
~CacheMemory();
|
||||
virtual ~CacheMemory();
|
||||
|
||||
/// @brief Add a Frame to the cache
|
||||
/// @param frame The openshot::Frame object needing to be cached.
|
||||
|
||||
@@ -112,7 +112,10 @@ namespace openshot {
|
||||
|
||||
// File Reader object
|
||||
ReaderBase* reader;
|
||||
bool manage_reader;
|
||||
|
||||
/// If we allocated a reader, we store it here to free it later
|
||||
/// (reader member variable itself may have been replaced)
|
||||
ReaderBase* allocated_reader;
|
||||
|
||||
/// Adjust frame number minimum value
|
||||
int64_t adjust_frame_number_minimum(int64_t frame_number);
|
||||
@@ -160,7 +163,7 @@ namespace openshot {
|
||||
Clip(ReaderBase* new_reader);
|
||||
|
||||
/// Destructor
|
||||
~Clip();
|
||||
virtual ~Clip();
|
||||
|
||||
/// @brief Add an effect to the clip
|
||||
/// @param effect Add an effect to the clip. An effect can modify the audio or video of an openshot::Frame.
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace openshot {
|
||||
|
||||
/// Constructor for the base clip
|
||||
ClipBase() { };
|
||||
virtual ~ClipBase();
|
||||
|
||||
// Compare a clip using the Position() property
|
||||
bool operator< ( ClipBase& a) { return (Position() < a.Position()); }
|
||||
|
||||
@@ -64,6 +64,8 @@ namespace openshot
|
||||
/// Constructor for DummyReader.
|
||||
DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration);
|
||||
|
||||
virtual ~DummyReader();
|
||||
|
||||
/// Close File
|
||||
void Close();
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace openshot {
|
||||
FFmpegReader(string path, bool inspect_reader);
|
||||
|
||||
/// Destructor
|
||||
~FFmpegReader();
|
||||
virtual ~FFmpegReader();
|
||||
|
||||
/// Close File
|
||||
void Close();
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace openshot
|
||||
Frame& operator= (const Frame& other);
|
||||
|
||||
/// Destructor
|
||||
~Frame();
|
||||
virtual ~Frame();
|
||||
|
||||
/// Add (or replace) pixel data to the frame (based on a solid color)
|
||||
void AddColor(int new_width, int new_height, string new_color);
|
||||
@@ -249,6 +249,9 @@ namespace openshot
|
||||
/// Get pixel data (for only a single scan-line)
|
||||
const unsigned char* GetPixels(int row);
|
||||
|
||||
/// Check a specific pixel color value (returns True/False)
|
||||
bool CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold);
|
||||
|
||||
/// Get height of image
|
||||
int GetHeight();
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace openshot
|
||||
FrameMapper(ReaderBase *reader, Fraction target_fps, PulldownType target_pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout);
|
||||
|
||||
/// Destructor
|
||||
~FrameMapper();
|
||||
virtual ~FrameMapper();
|
||||
|
||||
/// Change frame rate or audio mapping details
|
||||
void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout);
|
||||
@@ -213,6 +213,9 @@ namespace openshot
|
||||
/// Get the current reader
|
||||
ReaderBase* Reader();
|
||||
|
||||
/// Set the current reader
|
||||
void Reader(ReaderBase *new_reader) { reader = new_reader; }
|
||||
|
||||
/// Resample audio and map channels (if needed)
|
||||
void ResampleMappedAudio(std::shared_ptr<Frame> frame, int64_t original_frame_number);
|
||||
|
||||
|
||||
@@ -65,9 +65,10 @@ namespace openshot
|
||||
{
|
||||
private:
|
||||
string path;
|
||||
std::shared_ptr<QImage> image; ///> Original image (full quality)
|
||||
std::shared_ptr<QImage> cached_image; ///> Scaled for performance
|
||||
bool is_open;
|
||||
std::shared_ptr<QImage> image; ///> Original image (full quality)
|
||||
std::shared_ptr<QImage> cached_image; ///> Scaled for performance
|
||||
bool is_open; ///> Is Reader opened
|
||||
QSize max_size; ///> Current max_size as calculated with Clip properties
|
||||
|
||||
public:
|
||||
|
||||
@@ -80,6 +81,8 @@ namespace openshot
|
||||
/// when you are inflating the object using JSON after instantiating it.
|
||||
QtImageReader(string path, bool inspect_reader);
|
||||
|
||||
virtual ~QtImageReader();
|
||||
|
||||
/// Close File
|
||||
void Close();
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ namespace openshot
|
||||
/// Constructor for the base reader, where many things are initialized.
|
||||
ReaderBase();
|
||||
|
||||
virtual ~ReaderBase();
|
||||
|
||||
/// Information about the current media file
|
||||
ReaderInfo info;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QPainter>
|
||||
#include "CacheBase.h"
|
||||
@@ -152,6 +153,8 @@ namespace openshot {
|
||||
map<Clip*, Clip*> open_clips; ///<List of 'opened' clips on this timeline
|
||||
list<EffectBase*> effects; ///<List of clips on this timeline
|
||||
CacheBase *final_cache; ///<Final cache of timeline frames
|
||||
set<FrameMapper*> allocated_frame_mappers; ///< all the frame mappers we allocated and must free
|
||||
bool managed_cache; ///< Does this timeline instance manage the cache object
|
||||
|
||||
/// Process a new layer of video or audio
|
||||
void add_layer(std::shared_ptr<Frame> new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume);
|
||||
@@ -205,6 +208,8 @@ namespace openshot {
|
||||
/// @param channel_layout The channel layout (i.e. mono, stereo, 3 point surround, etc...)
|
||||
Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout);
|
||||
|
||||
virtual ~Timeline();
|
||||
|
||||
/// @brief Add an openshot::Clip to the timeline
|
||||
/// @param clip Add an openshot::Clip to the timeline. A clip can contain any type of Reader.
|
||||
void AddClip(Clip* clip);
|
||||
@@ -237,7 +242,8 @@ namespace openshot {
|
||||
/// Get the cache object used by this reader
|
||||
CacheBase* GetCache() { return final_cache; };
|
||||
|
||||
/// Get the cache object used by this reader
|
||||
/// Set the cache object used by this reader. You must now manage the lifecycle
|
||||
/// of this cache object though (Timeline will not delete it for you).
|
||||
void SetCache(CacheBase* new_cache);
|
||||
|
||||
/// Get an openshot::Frame object for a specific frame number of this timeline.
|
||||
|
||||
@@ -42,6 +42,9 @@ CacheBase::CacheBase(int64_t max_bytes) : max_bytes(max_bytes) {
|
||||
cacheCriticalSection = new CriticalSection();
|
||||
};
|
||||
|
||||
CacheBase::~CacheBase() {
|
||||
};
|
||||
|
||||
// Set maximum bytes to a different amount based on a ReaderInfo struct
|
||||
void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels)
|
||||
{
|
||||
@@ -69,4 +72,4 @@ void CacheBase::SetJsonValue(Json::Value root) {
|
||||
// Set data from Json (if key is found)
|
||||
if (!root["max_bytes"].isNull())
|
||||
max_bytes = atoll(root["max_bytes"].asString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
19
src/Clip.cpp
19
src/Clip.cpp
@@ -101,9 +101,6 @@ void Clip::init_settings()
|
||||
// Init audio and video overrides
|
||||
has_audio = Keyframe(-1.0);
|
||||
has_video = Keyframe(-1.0);
|
||||
|
||||
// Default pointers
|
||||
manage_reader = false;
|
||||
}
|
||||
|
||||
// Init reader's rotation (if any)
|
||||
@@ -131,14 +128,14 @@ void Clip::init_reader_rotation() {
|
||||
}
|
||||
|
||||
// Default Constructor for a clip
|
||||
Clip::Clip() : reader(NULL), resampler(NULL), audio_cache(NULL)
|
||||
Clip::Clip() : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL)
|
||||
{
|
||||
// Init all default settings
|
||||
init_settings();
|
||||
}
|
||||
|
||||
// Constructor with reader
|
||||
Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_cache(NULL)
|
||||
Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader(new_reader), allocated_reader(NULL)
|
||||
{
|
||||
// Init all default settings
|
||||
init_settings();
|
||||
@@ -152,7 +149,7 @@ Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_
|
||||
}
|
||||
|
||||
// Constructor with filepath
|
||||
Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL)
|
||||
Clip::Clip(string path) : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL)
|
||||
{
|
||||
// Init all default settings
|
||||
init_settings();
|
||||
@@ -194,7 +191,7 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL)
|
||||
// Update duration
|
||||
if (reader) {
|
||||
End(reader->info.duration);
|
||||
manage_reader = true;
|
||||
allocated_reader = reader;
|
||||
init_reader_rotation();
|
||||
}
|
||||
}
|
||||
@@ -203,9 +200,9 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL)
|
||||
Clip::~Clip()
|
||||
{
|
||||
// Delete the reader if clip created it
|
||||
if (manage_reader && reader) {
|
||||
delete reader;
|
||||
reader = NULL;
|
||||
if (allocated_reader) {
|
||||
delete allocated_reader;
|
||||
allocated_reader = NULL;
|
||||
}
|
||||
|
||||
// Close the resampler
|
||||
@@ -968,7 +965,7 @@ void Clip::SetJsonValue(Json::Value root) {
|
||||
// mark as managed reader and set parent
|
||||
if (reader) {
|
||||
reader->SetClip(this);
|
||||
manage_reader = true;
|
||||
allocated_reader = reader;
|
||||
}
|
||||
|
||||
// Re-Open reader (if needed)
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
using namespace openshot;
|
||||
|
||||
ClipBase::~ClipBase() {
|
||||
}
|
||||
|
||||
// Generate Json::JsonValue for this object
|
||||
Json::Value ClipBase::JsonValue() {
|
||||
|
||||
@@ -108,4 +111,4 @@ Json::Value ClipBase::add_property_choice_json(string name, int value, int selec
|
||||
|
||||
// return JsonValue
|
||||
return new_choice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, i
|
||||
Close();
|
||||
}
|
||||
|
||||
DummyReader::~DummyReader() {
|
||||
}
|
||||
|
||||
// Open image file
|
||||
void DummyReader::Open()
|
||||
{
|
||||
|
||||
@@ -576,6 +576,12 @@ void FFmpegReader::Close() {
|
||||
|
||||
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
|
||||
|
||||
if (packet) {
|
||||
// Remove previous packet before getting next one
|
||||
RemoveAVPacket(packet);
|
||||
packet = NULL;
|
||||
}
|
||||
|
||||
// Close the codec
|
||||
if (info.has_video) {
|
||||
avcodec_flush_buffers(pCodecCtx);
|
||||
@@ -624,6 +630,8 @@ void FFmpegReader::Close() {
|
||||
seek_video_frame_found = 0;
|
||||
current_video_frame = 0;
|
||||
has_missing_frames = false;
|
||||
|
||||
last_video_frame.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,6 +1036,8 @@ int FFmpegReader::GetNextPacket() {
|
||||
// Update current packet pointer
|
||||
packet = next_packet;
|
||||
}
|
||||
else
|
||||
delete next_packet;
|
||||
}
|
||||
// Return if packet was found (or error number)
|
||||
return found_packet;
|
||||
@@ -1063,7 +1073,7 @@ bool FFmpegReader::GetAVFrame() {
|
||||
{
|
||||
next_frame2 = next_frame;
|
||||
}
|
||||
pFrame = new AVFrame();
|
||||
pFrame = AV_ALLOCATE_FRAME();
|
||||
while (ret >= 0) {
|
||||
ret = avcodec_receive_frame(pCodecCtx, next_frame2);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
@@ -1110,11 +1120,13 @@ bool FFmpegReader::GetAVFrame() {
|
||||
#else
|
||||
avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
|
||||
|
||||
// always allocate pFrame (because we do that in the ffmpeg >= 3.2 as well); it will always be freed later
|
||||
pFrame = AV_ALLOCATE_FRAME();
|
||||
|
||||
// is frame finished
|
||||
if (frameFinished) {
|
||||
// AVFrames are clobbered on the each call to avcodec_decode_video, so we
|
||||
// must make a copy of the image data before this method is called again.
|
||||
pFrame = AV_ALLOCATE_FRAME();
|
||||
avpicture_alloc((AVPicture *) pFrame, pCodecCtx->pix_fmt, info.width, info.height);
|
||||
av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width,
|
||||
info.height);
|
||||
@@ -1206,6 +1218,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
|
||||
int width = info.width;
|
||||
int64_t video_length = info.video_length;
|
||||
AVFrame *my_frame = pFrame;
|
||||
pFrame = NULL;
|
||||
|
||||
// Add video frame to list of processing video frames
|
||||
const GenericScopedLock <CriticalSection> lock(processingCriticalSection);
|
||||
|
||||
@@ -884,9 +884,8 @@ void FFmpegWriter::flush_encoders() {
|
||||
}
|
||||
|
||||
// Close the video codec
|
||||
void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) {
|
||||
AV_FREE_CONTEXT(video_codec);
|
||||
video_codec = NULL;
|
||||
void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st)
|
||||
{
|
||||
#if IS_FFMPEG_3_2
|
||||
// #if defined(__linux__)
|
||||
if (hw_en_on && hw_en_supported) {
|
||||
@@ -900,10 +899,8 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) {
|
||||
}
|
||||
|
||||
// Close the audio codec
|
||||
void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) {
|
||||
AV_FREE_CONTEXT(audio_codec);
|
||||
audio_codec = NULL;
|
||||
|
||||
void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st)
|
||||
{
|
||||
// Clear buffers
|
||||
delete[] samples;
|
||||
delete[] audio_outbuf;
|
||||
@@ -942,12 +939,6 @@ void FFmpegWriter::Close() {
|
||||
if (image_rescalers.size() > 0)
|
||||
RemoveScalers();
|
||||
|
||||
// Free the streams
|
||||
for (int i = 0; i < oc->nb_streams; i++) {
|
||||
av_freep(AV_GET_CODEC_ATTRIBUTES(&oc->streams[i], &oc->streams[i]));
|
||||
av_freep(&oc->streams[i]);
|
||||
}
|
||||
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
/* close the output file */
|
||||
avio_close(oc->pb);
|
||||
@@ -957,8 +948,9 @@ void FFmpegWriter::Close() {
|
||||
write_video_count = 0;
|
||||
write_audio_count = 0;
|
||||
|
||||
// Free the context
|
||||
av_freep(&oc);
|
||||
// Free the context which frees the streams too
|
||||
avformat_free_context(oc);
|
||||
oc = NULL;
|
||||
|
||||
// Close writer
|
||||
is_open = false;
|
||||
|
||||
@@ -120,7 +120,7 @@ void Frame::DeepCopy(const Frame& other)
|
||||
wave_image = std::shared_ptr<QImage>(new QImage(*(other.wave_image)));
|
||||
}
|
||||
|
||||
// Descructor
|
||||
// Destructor
|
||||
Frame::~Frame() {
|
||||
// Clear all pointers
|
||||
image.reset();
|
||||
@@ -480,6 +480,28 @@ const unsigned char* Frame::GetPixels(int row)
|
||||
return image->scanLine(row);
|
||||
}
|
||||
|
||||
// Check a specific pixel color value (returns True/False)
|
||||
bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold) {
|
||||
int col_pos = col * 4; // Find column array position
|
||||
if (!image || row < 0 || row >= (height - 1) ||
|
||||
col_pos < 0 || col_pos >= (width - 1) ) {
|
||||
// invalid row / col
|
||||
return false;
|
||||
}
|
||||
// Check pixel color
|
||||
const unsigned char* pixels = GetPixels(row);
|
||||
if (pixels[col_pos + 0] >= (red - threshold) && pixels[col_pos + 0] <= (red + threshold) &&
|
||||
pixels[col_pos + 1] >= (green - threshold) && pixels[col_pos + 1] <= (green + threshold) &&
|
||||
pixels[col_pos + 2] >= (blue - threshold) && pixels[col_pos + 2] <= (blue + threshold) &&
|
||||
pixels[col_pos + 3] >= (alpha - threshold) && pixels[col_pos + 3] <= (alpha + threshold)) {
|
||||
// Pixel color matches successfully
|
||||
return true;
|
||||
} else {
|
||||
// Pixel color does not match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set Pixel Aspect Ratio
|
||||
void Frame::SetPixelRatio(int num, int den)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,8 @@ FrameMapper::~FrameMapper() {
|
||||
if (is_open)
|
||||
// Auto Close if not already
|
||||
Close();
|
||||
|
||||
reader = NULL;
|
||||
}
|
||||
|
||||
/// Get the current reader
|
||||
@@ -649,6 +651,16 @@ void FrameMapper::Close()
|
||||
// Close internal reader
|
||||
reader->Close();
|
||||
|
||||
// Clear the fields & frames lists
|
||||
fields.clear();
|
||||
frames.clear();
|
||||
|
||||
// Mark as dirty
|
||||
is_dirty = true;
|
||||
|
||||
// Clear cache
|
||||
final_cache.Clear();
|
||||
|
||||
// Deallocate resample buffer
|
||||
if (avr) {
|
||||
SWR_CLOSE(avr);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user