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 }