Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/xstudio/atoms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(xstudio_session_atoms, FIRST_CUSTOM_ID + (200 * 4))
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, default_category_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, get_annotation_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, annotation_data_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, laser_stroke_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, get_bookmark_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, get_bookmarks_atom)
CAF_ADD_ATOM(xstudio_session_atoms, xstudio::bookmark, remove_bookmark_atom)
Expand Down
12 changes: 9 additions & 3 deletions include/xstudio/media/media_actor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,25 @@ class MediaSourceActor : public caf::event_based_actor {
const caf::uri &_uri,
const utility::FrameList &frame_list,
const utility::FrameRate &rate = utility::FrameRate(timebase::k_flicks_24fps),
const utility::Uuid &uuid = utility::Uuid());
const utility::Uuid &uuid = utility::Uuid(),
const utility::JsonStore &initial_json =
utility::JsonStore(R"({"colour_pipeline": {}})"_json));
MediaSourceActor(
caf::actor_config &cfg,
const std::string &name,
const std::string &reader,
const utility::MediaReference &media_reference,
const utility::Uuid &uuid = utility::Uuid());
const utility::Uuid &uuid = utility::Uuid(),
const utility::JsonStore &initial_json =
utility::JsonStore(R"({"colour_pipeline": {}})"_json));
MediaSourceActor(
caf::actor_config &cfg,
const std::string &name = "Unnamed",
const caf::uri &_uri = caf::uri(),
const utility::FrameRate &rate = utility::FrameRate(timebase::k_flicks_24fps),
const utility::Uuid &uuid = utility::Uuid());
const utility::Uuid &uuid = utility::Uuid(),
const utility::JsonStore &initial_json =
utility::JsonStore(R"({"colour_pipeline": {}})"_json));
MediaSourceActor(caf::actor_config &cfg, const utility::JsonStore &jsn);
~MediaSourceActor() override = default;

Expand Down
2 changes: 1 addition & 1 deletion include/xstudio/media_reader/audio_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class AudioBuffer : public Buffer {
}*/

void stretch_samples(const uint64_t new_num_samples);

void
set_new_sample_rate(const uint64_t new_sample_rate, const timebase::flicks &exact_duration);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CachingMediaReaderActor : public caf::event_based_actor {
bool urgent_worker_busy_ = {false};

caf::actor pick_precache_worker() {
auto r = precache_workers_[next_precache_worker_];
auto r = precache_workers_[next_precache_worker_];
next_precache_worker_ = (next_precache_worker_ + 1) % precache_workers_.size();
return r;
}
Expand Down
5 changes: 3 additions & 2 deletions include/xstudio/media_reader/frame_request_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ class FrameRequestQueue {
* @brief Get the next ordered frame request
*
*/
std::optional<FrameRequest>
pop_request(const std::map<utility::Uuid, int> &exclude_playheads, const size_t max_num_inflight_requests);
std::optional<FrameRequest> pop_request(
const std::map<utility::Uuid, int> &exclude_playheads,
const size_t max_num_inflight_requests);

/**
* @brief Add a request to the queue
Expand Down
16 changes: 9 additions & 7 deletions include/xstudio/media_reader/media_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ namespace media_reader {
// this allows the cacheing m,edia reader actor to find out if
// it can spawn multiple readers to read a given source in parallel or not.
// For example, EXR benefits from multiple readers while ffmpeg does not
// because motion compressed video formats are not well served by multiple readers.
// because motion compressed video formats are not well served by multiple
// readers.
return media_reader_.prefer_sequential_access();
},

Expand Down Expand Up @@ -208,19 +209,20 @@ namespace media_reader {
[=](media_reader::get_thumbnail_atom,
media::AVFrameID mptr,
const size_t thumb_size) -> result<thumbnail::ThumbnailBufferPtr> {

try {

if (mptr.stream_id() == "auto video") {
// special case where we don't have a full Media object but
// need a thumbnail (FileBrowser plugin, for example). We
// special case where we don't have a full Media object but
// need a thumbnail (FileBrowser plugin, for example). We
// must pick the middle frame for the stream and the first
// video stream in the set.
const auto stream_details = media_reader_.detail(mptr.uri()).streams_;
const auto stream_details =
media_reader_.detail(mptr.uri()).streams_;
for (const auto &sd : stream_details) {
if (sd.media_type_ == media::MediaType::MT_IMAGE) {
mptr = media::AVFrameID(mptr.uri(),
sd.duration_.frames()/2,
mptr = media::AVFrameID(
mptr.uri(),
sd.duration_.frames() / 2,
mptr.first_frame(),
mptr.frame_status(),
0,
Expand Down
3 changes: 2 additions & 1 deletion include/xstudio/module/attribute_role_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ class AttributeData {
rt = true;
} else {
std::stringstream msg;
msg << "Attribute role data is type " << data_.type().name() << " doesn't match incoming data.";
msg << "Attribute role data is type " << data_.type().name()
<< " doesn't match incoming data.";
throw std::runtime_error(msg.str().c_str());
}
return rt;
Expand Down
1 change: 0 additions & 1 deletion include/xstudio/ui/qml/thumbnail_provider_ui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ class ThumbnailResponse : public QQuickImageResponse {
auto [i, e] = watcher_.result();

if (not e.isEmpty()) {
qDebug() << e;
error_ = "Thumbnail does not exist 2.";
bad_thumbs_.insert(id_, QDateTime::currentDateTime());
} else {
Expand Down
13 changes: 7 additions & 6 deletions include/xstudio/utility/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@ void print_on_exit(

// std::string filemanager_show_uris(const std::vector<caf::uri> &uris);

caf::uri posix_path_to_uri(const std::string &path, const bool abspath = false, const bool remap = true);
caf::uri
posix_path_to_uri(const std::string &path, const bool abspath = false, const bool remap = true);

caf::uri
parse_cli_posix_path(const std::string &path, FrameList &frame_list, const bool scan = false);
Expand Down Expand Up @@ -355,7 +356,7 @@ std::string uri_decode(const std::string &eString);
// this is WRONG on purpose, as caf::uri are buggy.
// the path component needs to be escaped, even when it's a file::
std::string uri_encode(const std::string &s);
std::string uri_to_posix_path(const caf::uri &uri, const bool remap=true);
std::string uri_to_posix_path(const caf::uri &uri, const bool remap = true);

// can only get signature for posix urls..
inline std::array<uint8_t, 16> get_signature(const caf::uri &uri) {
Expand Down Expand Up @@ -673,9 +674,9 @@ void add_remap_file_path(const std::string &from, const std::string &to);
// ]
void setup_filepath_remap_regex(const utility::JsonStore &);

// MD5 hash of a byte buffer. Returns the 16-byte digest.
// Uses OpenSSL EVP API on OpenSSL >= 1.1.0 and falls back to the legacy
// MD5_* API on older versions.
std::array<unsigned char, 16> md5_hash(const void *data, std::size_t size);
// MD5 hash of a byte buffer. Returns the 16-byte digest.
// Uses OpenSSL EVP API on OpenSSL >= 1.1.0 and falls back to the legacy
// MD5_* API on older versions.
std::array<unsigned char, 16> md5_hash(const void *data, std::size_t size);

} // namespace xstudio::utility
16 changes: 8 additions & 8 deletions include/xstudio/utility/path_remapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace xstudio::utility {
class PathRemapper {

public:
PathRemapper() = default;
PathRemapper() = default;
virtual ~PathRemapper() = default;

std::string forwards(const std::string &path);
Expand All @@ -25,15 +25,15 @@ class PathRemapper {
void add_path_mapping(const std::string &from, const std::string &to);

private:
std::string remap(const std::string &path, const bool forwards);
std::string remap(const std::string &path, const bool forwards);

std::mutex mutex_;
std::mutex mutex_;

std::vector<std::pair<std::regex, std::string>> forward_regex_;
std::vector<std::pair<std::regex, std::string>> backward_regex_;
std::vector<std::pair<std::regex, std::string>> forward_regex_;
std::vector<std::pair<std::regex, std::string>> backward_regex_;

std::map<std::string, std::string> forward_map_;
std::map<std::string, std::string> backward_map_;
std::map<std::string, std::string> forward_map_;
std::map<std::string, std::string> backward_map_;
};

}
} // namespace xstudio::utility
36 changes: 21 additions & 15 deletions include/xstudio/utility/string_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,28 +155,34 @@ std::string make_hex_string(
}

template <typename T>
inline std::string join_as_string(const std::vector<T> &items, const std::string &separator) {
inline std::string join_as_string(
const std::vector<T> &items, const std::string &separator, const bool skip_empty = false) {
std::string result;
if (!items.empty()) {
result = to_string(items[0]);
if (items.size() > 1) {
for (size_t i = 1; i < items.size(); i++)
result += separator + to_string(items[i]);
}

for (const auto &i : items) {
const auto i_as_string = to_string(i);
if (skip_empty and i_as_string.empty())
continue;
if (not result.empty())
result += separator;
result += i_as_string;
}

return result;
}

inline std::string
join_as_string(const std::vector<std::string> &items, const std::string &separator) {
inline std::string join_as_string(
const std::vector<std::string> &items,
const std::string &separator,
const bool skip_empty = false) {
std::string result;
if (!items.empty()) {
result = items[0];
if (items.size() > 1) {
for (size_t i = 1; i < items.size(); i++)
result += separator + items[i];
}

for (const auto &i : items) {
if (skip_empty and i.empty())
continue;
if (not result.empty())
result += separator;
result += i;
}

return result;
Expand Down
2 changes: 1 addition & 1 deletion python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ else()
else()
add_custom_command(OUTPUT ${OUTPUT}/lib/${PYTHONVP}/site-packages/xstudio/api
COMMAND ${Python_EXECUTABLE}
ARGS setup.py install --old-and-unmanageable --prefix=${OUTPUT}
ARGS -m pip install . --prefix=${OUTPUT}
DEPENDS __pybind_xstudio ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in)
endif()

Expand Down
8 changes: 7 additions & 1 deletion python/src/xstudio/api/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ def __init__(
self.menu_item_ids = []
self.hotkey_callbacks = {}
self._uuid = None
self.message_handler_id = None

for attr_uuid in attr_uuids:
attr_wrapper = ModuleAttribute(
Expand All @@ -221,10 +222,15 @@ def setup_message_handler(self):
# this call gets the event group for Module attribute change events
remote_event_group = self.connection.request_receive(self.remote, get_event_group_atom(), True)[0]

self.connection.link.add_message_callback(
self.message_handler_id = self.connection.link.add_message_callback(
remote_event_group, self.message_handler
)

def cleanup_message_handler(self):
if self.message_handler_id is not None:
self.connection.link.remove_message_callback(self.message_handler_id)
self.message_handler_id = None

def connect_to_ui(self):
"""Call this method to 'activate' the plugin and forward live data about
the attributes to the UI layer. QML code that builds widgets and so-on
Expand Down
6 changes: 2 additions & 4 deletions python/src/xstudio/api/session/playhead/playhead_selection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
from xstudio.core import monitored_atom, Uuid, MT_IMAGE, MT_AUDIO
from xstudio.core import monitored_atom, Uuid, MT_IMAGE, MT_AUDIO, VectorUuid
from xstudio.core import move_atom, remove_atom, actor, select_all_media_atom
from xstudio.core import select_media_atom, get_selected_sources_atom

Expand Down Expand Up @@ -67,9 +67,7 @@ def set_selection(self, media_uuids):
Returns:
success(bool): Selection set.
"""
self.connection.request_receive(self.remote, select_media_atom())
for media_uuid in media_uuids:
self.connection.request_receive(self.remote, select_media_atom(), media_uuid)
self.connection.request_receive(self.remote, select_media_atom(), VectorUuid(media_uuids))
return True

def insert(self, media, before=Uuid(), media_type=MT_IMAGE):
Expand Down
8 changes: 4 additions & 4 deletions python/src/xstudio/api/session/playlist/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def add_media_with_audio(self, image_path, audio_path, audio_offset=0):

return media

def add_media(self, path, frame_list=None):
def add_media(self, path, frame_list=None, before_uuid=Uuid()):
"""Add media from path.

Args:
Expand All @@ -125,16 +125,16 @@ def add_media(self, path, frame_list=None):
media(Media): Media.
"""
if isinstance(path, URI):
result = self.connection.request_receive(self.remote, add_media_atom(), path, False, Uuid())[0]
result = self.connection.request_receive(self.remote, add_media_atom(), path, False, before_uuid)[0]
else:
ppp = parse_posix_path(path)
name = Path(path).name.split(".", 1)[0] # this is to match what happens internally with a URI above

if not str(ppp[1]) and frame_list is None:
result = self.connection.request_receive(self.remote, add_media_atom(), name, ppp[0], Uuid())[0]
result = self.connection.request_receive(self.remote, add_media_atom(), path, ppp[0], before_uuid)[0]
else:
result = self.connection.request_receive(
self.remote, add_media_atom(), name, ppp[0], ppp[1] if frame_list is None else frame_list, Uuid()
self.remote, add_media_atom(), path, ppp[0], ppp[1] if frame_list is None else frame_list, before_uuid
)[0]

return Media(self.connection, result.actor, result.uuid)
Expand Down
4 changes: 3 additions & 1 deletion python/src/xstudio/api/session/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def viewed_container(self):
"""

result = self.connection.request_receive(self.remote, viewport_active_media_container_atom())[0]
if not result.actor:
return None
c = Container(self.connection, result.actor)

if c.type == "Timeline":
Expand Down Expand Up @@ -232,7 +234,7 @@ def playlists(self):

def create_hidden_playlist(self, name="Hidden Playlist"):
"""Create hidden playlist. This playlist can be used to put transient
media on screen (e.g. preview mode of File System Browser plugin). The
media on screen (e.g. preview mode of File Browser plugin). The
playlist is not added to the session and is not visible in the playlists
interface and is not serialised into the session file.

Expand Down
Loading
Loading