File indexing completed on 2024-04-28 04:52:05
0001 /* 0002 SPDX-FileCopyrightText: 2015 Meltytech LLC 0003 SPDX-FileCopyrightText: 2015 Brian Matherly <code@brianmatherly.com> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 #include "sharedframe.h" 0008 #include <mutex> 0009 0010 void destroyFrame(void *p) 0011 { 0012 delete static_cast<Mlt::Frame *>(p); 0013 } 0014 0015 class FrameData : public QSharedData 0016 { 0017 public: 0018 FrameData() 0019 : f(nullptr) 0020 { 0021 } 0022 explicit FrameData(Mlt::Frame &frame) 0023 : f(frame) 0024 { 0025 } 0026 ~FrameData() = default; 0027 0028 Mlt::Frame f; 0029 std::mutex m; 0030 0031 private: 0032 Q_DISABLE_COPY(FrameData) 0033 }; 0034 0035 SharedFrame::SharedFrame() 0036 : d(nullptr) 0037 { 0038 } 0039 0040 SharedFrame::SharedFrame(Mlt::Frame &frame) 0041 : d(new FrameData(frame)) 0042 { 0043 } 0044 0045 SharedFrame::SharedFrame(const SharedFrame &other) 0046 0047 = default; 0048 0049 SharedFrame::~SharedFrame() = default; 0050 0051 SharedFrame &SharedFrame::operator=(const SharedFrame &other) = default; 0052 0053 bool SharedFrame::is_valid() const 0054 { 0055 return d && d->f.is_valid(); 0056 } 0057 0058 Mlt::Frame SharedFrame::clone(bool audio, bool image, bool alpha) const 0059 { 0060 // TODO: Consider moving this implementation into MLT. 0061 // It could be added to mlt_frame as an alternative to: 0062 // mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ); 0063 // It could also be added to Mlt::Frame as a const function. 0064 void *data = nullptr; 0065 void *copy = nullptr; 0066 int size = 0; 0067 Mlt::Frame cloneFrame(mlt_frame_init(nullptr)); 0068 cloneFrame.inherit(d->f); 0069 cloneFrame.set("_producer", d->f.get_data("_producer", size), 0, nullptr, nullptr); 0070 cloneFrame.set("movit.convert", d->f.get_data("movit.convert", size), 0, nullptr, nullptr); 0071 cloneFrame.get_frame()->convert_image = d->f.get_frame()->convert_image; 0072 cloneFrame.get_frame()->convert_audio = d->f.get_frame()->convert_audio; 0073 0074 data = d->f.get_data("audio", size); 0075 if (audio && (data != nullptr)) { 0076 if (size == 0) { 0077 size = mlt_audio_format_size(get_audio_format(), get_audio_samples(), get_audio_channels()); 0078 } 0079 copy = mlt_pool_alloc(size); 0080 memcpy(copy, data, size_t(size)); 0081 cloneFrame.set("audio", copy, size, mlt_pool_release); 0082 } else { 0083 cloneFrame.set("audio", 0); 0084 cloneFrame.set("audio_format", mlt_audio_none); 0085 cloneFrame.set("audio_channels", 0); 0086 cloneFrame.set("audio_frequency", 0); 0087 cloneFrame.set("audio_samples", 0); 0088 } 0089 0090 data = d->f.get_data("image", size); 0091 if (image && (data != nullptr)) { 0092 if (size == 0) { 0093 size = mlt_image_format_size(get_image_format(), get_image_width(), get_image_height(), nullptr); 0094 } 0095 copy = mlt_pool_alloc(size); 0096 memcpy(copy, data, size_t(size)); 0097 cloneFrame.set("image", copy, size, mlt_pool_release); 0098 } else { 0099 cloneFrame.set("image", 0); 0100 cloneFrame.set("image_format", mlt_image_none); 0101 cloneFrame.set("width", 0); 0102 cloneFrame.set("height", 0); 0103 } 0104 0105 data = d->f.get_data("alpha", size); 0106 if (alpha && (data != nullptr)) { 0107 if (size == 0) { 0108 size = get_image_width() * get_image_height(); 0109 } 0110 copy = mlt_pool_alloc(size); 0111 memcpy(copy, data, size_t(size)); 0112 cloneFrame.set("alpha", copy, size, mlt_pool_release); 0113 } else { 0114 cloneFrame.set("alpha", 0); 0115 } 0116 0117 // Release the reference on the initial frame so that the returned frame 0118 // only has one reference. 0119 mlt_frame_close(cloneFrame.get_frame()); 0120 return cloneFrame; 0121 } 0122 0123 int SharedFrame::get_int(const char *name) const 0124 { 0125 return d->f.get_int(name); 0126 } 0127 0128 int64_t SharedFrame::get_int64(const char *name) const 0129 { 0130 return d->f.get_int64(name); 0131 } 0132 0133 double SharedFrame::get_double(const char *name) const 0134 { 0135 return d->f.get_double(name); 0136 } 0137 0138 char *SharedFrame::get(const char *name) const 0139 { 0140 return d->f.get(name); 0141 } 0142 0143 int SharedFrame::get_position() const 0144 { 0145 return d->f.get_position(); 0146 } 0147 0148 mlt_image_format SharedFrame::get_image_format() const 0149 { 0150 return mlt_image_format(d->f.get_int("format")); 0151 } 0152 0153 int SharedFrame::get_image_width() const 0154 { 0155 return d->f.get_int("width"); 0156 } 0157 0158 int SharedFrame::get_image_height() const 0159 { 0160 return d->f.get_int("height"); 0161 } 0162 0163 const uint8_t *SharedFrame::get_image(mlt_image_format format) const 0164 { 0165 mlt_image_format native_format = get_image_format(); 0166 int width = get_image_width(); 0167 int height = get_image_height(); 0168 uint8_t *image = nullptr; 0169 0170 if (format == mlt_image_none) { 0171 format = native_format; 0172 } 0173 0174 if (format == native_format) { 0175 // Native format is requested. Return frame image. 0176 image = static_cast<uint8_t *>(d->f.get_image(format, width, height, 0)); 0177 } else { 0178 // Non-native format is requested. Return a cached converted image. 0179 const char *formatName = mlt_image_format_name(format); 0180 // Convert to non-const so that the cache can be accessed/modified while 0181 // under lock. 0182 auto *nonConstData = const_cast<FrameData *>(d.data()); 0183 0184 nonConstData->m.lock(); 0185 0186 auto *cacheFrame = static_cast<Mlt::Frame *>(nonConstData->f.get_data(formatName)); 0187 if (cacheFrame == nullptr) { 0188 // A cached image does not exist, create one. 0189 // Make a non-deep clone of the frame (including convert function) 0190 mlt_frame cloneFrame = mlt_frame_clone(nonConstData->f.get_frame(), 0); 0191 cloneFrame->convert_image = nonConstData->f.get_frame()->convert_image; 0192 // Create a new cache frame 0193 cacheFrame = new Mlt::Frame(cloneFrame); 0194 // Release the reference on the clone 0195 // (now it is owned by the cache frame) 0196 mlt_frame_close(cloneFrame); 0197 // Save the cache frame as a property under the name of the image 0198 // format for later use. 0199 nonConstData->f.set(formatName, static_cast<void *>(cacheFrame), 0, destroyFrame); 0200 // Break a circular reference 0201 cacheFrame->clear("_cloned_frame"); 0202 } 0203 0204 // Get the image from the cache frame. 0205 // This will cause a conversion if it was just created. 0206 image = static_cast<uint8_t *>(cacheFrame->get_image(format, width, height, 0)); 0207 0208 nonConstData->m.unlock(); 0209 } 0210 return image; 0211 } 0212 0213 mlt_audio_format SharedFrame::get_audio_format() const 0214 { 0215 return mlt_audio_format(d->f.get_int("audio_format")); 0216 } 0217 0218 int SharedFrame::get_audio_channels() const 0219 { 0220 return d->f.get_int("audio_channels"); 0221 } 0222 0223 int SharedFrame::get_audio_frequency() const 0224 { 0225 return d->f.get_int("audio_frequency"); 0226 } 0227 0228 int SharedFrame::get_audio_samples() const 0229 { 0230 return d->f.get_int("audio_samples"); 0231 } 0232 0233 const int16_t *SharedFrame::get_audio() const 0234 { 0235 mlt_audio_format format = get_audio_format(); 0236 int frequency = get_audio_frequency(); 0237 int channels = get_audio_channels(); 0238 int samples = get_audio_samples(); 0239 return static_cast<int16_t *>(d->f.get_audio(format, frequency, channels, samples)); 0240 }