mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
refactor(videoframe): move all inline/template functions into source
This commit is contained in:
parent
07f5cf3a65
commit
f6a698bec5
|
@ -383,6 +383,140 @@ ToxYUVFrame VideoFrame::toToxYUVFrame(QSize frameSize)
|
|||
return toGenericObject(frameSize, AV_PIX_FMT_YUV420P, true, converter, ToxYUVFrame {0, 0, nullptr, nullptr, nullptr});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the ID for the given frame.
|
||||
*
|
||||
* Frame IDs are globally unique (with respect to the running instance).
|
||||
*
|
||||
* @return an integer representing the ID of this frame.
|
||||
*/
|
||||
VideoFrame::IDType VideoFrame::getFrameID() const
|
||||
{
|
||||
return frameID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the ID for the VideoSource which created this frame.
|
||||
*
|
||||
* @return an integer representing the ID of the VideoSource which created this frame.
|
||||
*/
|
||||
VideoFrame::IDType VideoFrame::getSourceID() const
|
||||
{
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a copy of the source VideoFrame's dimensions.
|
||||
*
|
||||
* @return QRect copy representing the source VideoFrame's dimensions.
|
||||
*/
|
||||
QRect VideoFrame::getSourceDimensions() const
|
||||
{
|
||||
return sourceDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a copy of the source VideoFormat's pixel format.
|
||||
*
|
||||
* @return integer copy representing the source VideoFrame's pixel format.
|
||||
*/
|
||||
int VideoFrame::getSourcePixelFormat() const
|
||||
{
|
||||
return sourcePixelFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructs a new FrameBufferKey with the given attributes.
|
||||
*
|
||||
* @param width the width of the frame.
|
||||
* @param height the height of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param lineAligned whether the linesize matches the width of the image.
|
||||
*/
|
||||
VideoFrame::FrameBufferKey::FrameBufferKey(const int pixFmt, const int width, const int height, const bool lineAligned)
|
||||
: frameWidth(width),
|
||||
frameHeight(height),
|
||||
pixelFormat(pixFmt),
|
||||
linesizeAligned(lineAligned){}
|
||||
|
||||
/**
|
||||
* @brief Comparison operator for FrameBufferKey.
|
||||
*
|
||||
* @param other instance to compare against.
|
||||
* @return true if instances are equivilent, false otherwise.
|
||||
*/
|
||||
bool VideoFrame::FrameBufferKey::operator==(const FrameBufferKey& other) const
|
||||
{
|
||||
return pixelFormat == other.pixelFormat &&
|
||||
frameWidth == other.frameWidth &&
|
||||
frameHeight == other.frameHeight &&
|
||||
linesizeAligned == other.linesizeAligned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Not equal to operator for FrameBufferKey.
|
||||
*
|
||||
* @param other instance to compare against
|
||||
* @return true if instances are not equivilent, false otherwise.
|
||||
*/
|
||||
bool VideoFrame::FrameBufferKey::operator!=(const FrameBufferKey& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Hash function for FrameBufferKey.
|
||||
*
|
||||
* This function computes a hash value for use with std::unordered_map.
|
||||
*
|
||||
* @param key the given instance to compute hash value of.
|
||||
* @return the hash of the given instance.
|
||||
*/
|
||||
size_t VideoFrame::FrameBufferKey::hash(const FrameBufferKey& key)
|
||||
{
|
||||
std::hash<int> intHasher;
|
||||
std::hash<bool> boolHasher;
|
||||
|
||||
// Use java-style hash function to combine fields
|
||||
// See: https://en.wikipedia.org/wiki/Java_hashCode%28%29#hashCode.28.29_in_general
|
||||
|
||||
size_t ret = 47;
|
||||
|
||||
ret = 37 * ret + intHasher(key.frameWidth);
|
||||
ret = 37 * ret + intHasher(key.frameHeight);
|
||||
ret = 37 * ret + intHasher(key.pixelFormat);
|
||||
ret = 37 * ret + boolHasher(key.linesizeAligned);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a key object based on given parameters.
|
||||
*
|
||||
* @param frameSize the given size of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param linesize the maximum linesize of the frame, may be larger than the width.
|
||||
* @return a FrameBufferKey object representing the key for the frameBuffer map.
|
||||
*/
|
||||
VideoFrame::FrameBufferKey VideoFrame::getFrameKey(const QSize& frameSize, const int pixFmt, const int linesize)
|
||||
{
|
||||
return getFrameKey(frameSize, pixFmt, frameSize.width() == linesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a key object based on given parameters.
|
||||
*
|
||||
* @param frameSize the given size of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param frameAligned true if the frame is aligned, false otherwise.
|
||||
* @return a FrameBufferKey object representing the key for the frameBuffer map.
|
||||
*/
|
||||
VideoFrame::FrameBufferKey VideoFrame::getFrameKey(const QSize& frameSize, const int pixFmt, const bool frameAligned)
|
||||
{
|
||||
return {frameSize.width(), frameSize.height(), pixFmt, frameAligned};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves an AVFrame derived from the source based on the given parameters without
|
||||
* obtaining a lock.
|
||||
|
@ -564,15 +698,71 @@ void VideoFrame::deleteFrameBuffer()
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a new FrameBufferKey with the given attributes.
|
||||
* @brief Converts this VideoFrame to a generic type T based on the given parameters and
|
||||
* supplied converter functions.
|
||||
*
|
||||
* @param width the width of the frame.
|
||||
* @param height the height of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param lineAligned whether the linesize matches the width of the image.
|
||||
* This function is used internally to create various toXObject functions that all follow the
|
||||
* same generation pattern (where XObject is some existing type like QImage).
|
||||
*
|
||||
* In order to create such a type, a object constructor function is required that takes the
|
||||
* generated AVFrame object and creates type T out of it. This function additionally requires
|
||||
* a null object of type T that represents an invalid/null object for when the generation
|
||||
* process fails (e.g. when the VideoFrame is no longer valid).
|
||||
*
|
||||
* @param dimensions the dimensions of the frame, must be valid.
|
||||
* @param pixelFormat the pixel format of the frame.
|
||||
* @param requireAligned true if the generated frame needs to be frame aligned, false otherwise.
|
||||
* @param objectConstructor a std::function that takes the generated AVFrame and converts it
|
||||
* to an object of type T.
|
||||
* @param nullObject an object of type T that represents the null/invalid object to be used
|
||||
* when the generation process fails.
|
||||
*/
|
||||
VideoFrame::FrameBufferKey::FrameBufferKey(const int pixFmt, const int width, const int height, const bool lineAligned)
|
||||
: frameWidth(width),
|
||||
frameHeight(height),
|
||||
pixelFormat(pixFmt),
|
||||
linesizeAligned(lineAligned){}
|
||||
template <typename T>
|
||||
T VideoFrame::toGenericObject(const QSize& dimensions, const int pixelFormat, const bool requireAligned,
|
||||
const std::function<T(AVFrame* const)> objectConstructor, const T& nullObject)
|
||||
{
|
||||
frameLock.lockForRead();
|
||||
|
||||
// We return nullObject if the VideoFrame is no longer valid
|
||||
if(frameBuffer.size() == 0)
|
||||
{
|
||||
frameLock.unlock();
|
||||
return nullObject;
|
||||
}
|
||||
|
||||
AVFrame* frame = retrieveAVFrame(dimensions, static_cast<int>(pixelFormat), requireAligned);
|
||||
|
||||
if(frame)
|
||||
{
|
||||
T ret = objectConstructor(frame);
|
||||
|
||||
frameLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// VideoFrame does not contain an AVFrame to spec, generate one here
|
||||
frame = generateAVFrame(dimensions, static_cast<int>(pixelFormat), requireAligned);
|
||||
|
||||
/*
|
||||
* We need to "upgrade" the lock to a write lock so we can update our frameBuffer map.
|
||||
*
|
||||
* It doesn't matter if another thread obtains the write lock before we finish since it is
|
||||
* likely writing to somewhere else. Worst-case scenario, we merely perform the generation
|
||||
* process twice, and discard the old result.
|
||||
*/
|
||||
frameLock.unlock();
|
||||
frameLock.lockForWrite();
|
||||
|
||||
storeAVFrame(frame, dimensions, static_cast<int>(pixelFormat));
|
||||
|
||||
T ret = objectConstructor(frame);
|
||||
|
||||
frameLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Explicitly specialize VideoFrame::toGenericObject() function
|
||||
template QImage VideoFrame::toGenericObject<QImage>(const QSize& dimensions, const int pixelFormat, const bool requireAligned,
|
||||
const std::function<QImage(AVFrame* const)> objectConstructor, const QImage& nullObject);
|
||||
template ToxYUVFrame VideoFrame::toGenericObject<ToxYUVFrame>(const QSize& dimensions, const int pixelFormat, const bool requireAligned,
|
||||
const std::function<ToxYUVFrame(AVFrame* const)> objectConstructor, const ToxYUVFrame& nullObject);
|
||||
|
|
|
@ -79,44 +79,10 @@ public:
|
|||
QImage toQImage(QSize frameSize = {});
|
||||
ToxYUVFrame toToxYUVFrame(QSize frameSize = {});
|
||||
|
||||
/**
|
||||
* @brief Returns the ID for the given frame.
|
||||
*
|
||||
* Frame IDs are globally unique (with respect to the running instance).
|
||||
*
|
||||
* @return an integer representing the ID of this frame.
|
||||
*/
|
||||
inline IDType getFrameID() const
|
||||
{
|
||||
return frameID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the ID for the VideoSource which created this frame.
|
||||
* @return an integer representing the ID of the VideoSource which created this frame.
|
||||
*/
|
||||
inline IDType getSourceID() const
|
||||
{
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a copy of the source VideoFrame's dimensions.
|
||||
* @return QRect copy representing the source VideoFrame's dimensions.
|
||||
*/
|
||||
inline QRect getSourceDimensions() const
|
||||
{
|
||||
return sourceDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a copy of the source VideoFormat's pixel format.
|
||||
* @return integer copy represetning the source VideoFrame's pixel format.
|
||||
*/
|
||||
inline int getSourcePixelFormat() const
|
||||
{
|
||||
return sourcePixelFormat;
|
||||
}
|
||||
IDType getFrameID() const;
|
||||
IDType getSourceID() const;
|
||||
QRect getSourceDimensions() const;
|
||||
int getSourcePixelFormat() const;
|
||||
|
||||
static constexpr int dataAlignment = 32;
|
||||
|
||||
|
@ -136,54 +102,10 @@ private:
|
|||
const FrameBufferKey& operator=(const FrameBufferKey&) = delete;
|
||||
const FrameBufferKey& operator=(FrameBufferKey&&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Comparison operator for FrameBufferKey.
|
||||
*
|
||||
* @param other instance to compare against.
|
||||
* @return true if instances are equivilent, false otherwise.
|
||||
*/
|
||||
inline bool operator==(const FrameBufferKey& other) const
|
||||
{
|
||||
return pixelFormat == other.pixelFormat &&
|
||||
frameWidth == other.frameWidth &&
|
||||
frameHeight == other.frameHeight &&
|
||||
linesizeAligned == other.linesizeAligned;
|
||||
}
|
||||
bool operator==(const FrameBufferKey& other) const;
|
||||
bool operator!=(const FrameBufferKey& other) const;
|
||||
|
||||
/**
|
||||
* @brief Not equal to operator for FrameBufferKey.
|
||||
*
|
||||
* @param other instance to compare against
|
||||
* @return true if instances are not equivilent, false otherwise.
|
||||
*/
|
||||
inline bool operator!=(const FrameBufferKey& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Hash function for class.
|
||||
*
|
||||
* This function computes a hash value for use with std::unordered_map.
|
||||
*
|
||||
* @param key the given instance to compute hash value of.
|
||||
* @return the hash of the given instance.
|
||||
*/
|
||||
static inline size_t hash(const FrameBufferKey& key)
|
||||
{
|
||||
std::hash<int> intHasher;
|
||||
std::hash<bool> boolHasher;
|
||||
|
||||
// Use java-style hash function to combine fields
|
||||
size_t ret = 47;
|
||||
|
||||
ret = 37 * ret + intHasher(key.frameWidth);
|
||||
ret = 37 * ret + intHasher(key.frameHeight);
|
||||
ret = 37 * ret + intHasher(key.pixelFormat);
|
||||
ret = 37 * ret + boolHasher(key.linesizeAligned);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static size_t hash(const FrameBufferKey& key);
|
||||
|
||||
public:
|
||||
const int frameWidth;
|
||||
|
@ -193,31 +115,8 @@ private:
|
|||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Generates a key object based on given parameters.
|
||||
*
|
||||
* @param frameSize the given size of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param linesize the maximum linesize of the frame, may be larger than the width.
|
||||
* @return a FrameBufferKey object representing the key for the frameBuffer map.
|
||||
*/
|
||||
static inline FrameBufferKey getFrameKey(const QSize& frameSize, const int pixFmt, const int linesize)
|
||||
{
|
||||
return getFrameKey(frameSize, pixFmt, frameSize.width() == linesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a key object based on given parameters.
|
||||
*
|
||||
* @param frameSize the given size of the frame.
|
||||
* @param pixFmt the pixel format of the frame.
|
||||
* @param frameAligned true if the frame is aligned, false otherwise.
|
||||
* @return a FrameBufferKey object representing the key for the frameBuffer map.
|
||||
*/
|
||||
static inline FrameBufferKey getFrameKey(const QSize& frameSize, const int pixFmt, const bool frameAligned)
|
||||
{
|
||||
return {frameSize.width(), frameSize.height(), pixFmt, frameAligned};
|
||||
}
|
||||
static FrameBufferKey getFrameKey(const QSize& frameSize, const int pixFmt, const int linesize);
|
||||
static FrameBufferKey getFrameKey(const QSize& frameSize, const int pixFmt, const bool frameAligned);
|
||||
|
||||
AVFrame* retrieveAVFrame(const QSize& dimensions, const int pixelFormat, const bool requireAligned);
|
||||
AVFrame* generateAVFrame(const QSize& dimensions, const int pixelFormat, const bool requireAligned);
|
||||
|
@ -225,69 +124,9 @@ private:
|
|||
|
||||
void deleteFrameBuffer();
|
||||
|
||||
/**
|
||||
* @brief Converts this VideoFrame to a generic type T based on the given parameters and
|
||||
* supplied converter functions.
|
||||
*
|
||||
* This function is used internally to create various toXObject functions that all follow the
|
||||
* same generation pattern (where XObject is some existing type like QImage).
|
||||
*
|
||||
* In order to create such a type, a object constructor function is required that takes the
|
||||
* generated AVFrame object and creates type T out of it. This function additionally requires
|
||||
* a null object of type T that represents an invalid/null object for when the generation
|
||||
* process fails (e.g. when the VideoFrame is no longer valid).
|
||||
*
|
||||
* @param dimensions the dimensions of the frame, must be valid.
|
||||
* @param pixelFormat the pixel format of the frame.
|
||||
* @param requireAligned true if the generated frame needs to be frame aligned, false otherwise.
|
||||
* @param objectConstructor a std::function that takes the generated AVFrame and converts it
|
||||
* to an object of type T.
|
||||
* @param nullObject an object of type T that represents the null/invalid object to be used
|
||||
* when the generation process fails.
|
||||
*/
|
||||
template <typename T>
|
||||
T toGenericObject(const QSize& dimensions, const int pixelFormat, const bool requireAligned,
|
||||
const std::function<T(AVFrame* const)> objectConstructor, const T& nullObject)
|
||||
{
|
||||
frameLock.lockForRead();
|
||||
|
||||
// We return nullObject if the VideoFrame is no longer valid
|
||||
if(frameBuffer.size() == 0)
|
||||
{
|
||||
frameLock.unlock();
|
||||
return nullObject;
|
||||
}
|
||||
|
||||
AVFrame* frame = retrieveAVFrame(dimensions, static_cast<int>(pixelFormat), requireAligned);
|
||||
|
||||
if(frame)
|
||||
{
|
||||
T ret = objectConstructor(frame);
|
||||
|
||||
frameLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// VideoFrame does not contain an AVFrame to spec, generate one here
|
||||
frame = generateAVFrame(dimensions, static_cast<int>(pixelFormat), requireAligned);
|
||||
|
||||
/*
|
||||
* We need to "upgrade" the lock to a write lock so we can update our frameBuffer map.
|
||||
*
|
||||
* It doesn't matter if another thread obtains the write lock before we finish since it is
|
||||
* likely writing to somewhere else. Worst-case scenario, we merely perform the generation
|
||||
* process twice, and discard the old result.
|
||||
*/
|
||||
frameLock.unlock();
|
||||
frameLock.lockForWrite();
|
||||
|
||||
storeAVFrame(frame, dimensions, static_cast<int>(pixelFormat));
|
||||
|
||||
T ret = objectConstructor(frame);
|
||||
|
||||
frameLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
const std::function<T(AVFrame* const)> objectConstructor, const T& nullObject);
|
||||
|
||||
private:
|
||||
// ID
|
||||
|
|
Loading…
Reference in New Issue
Block a user