1
0
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:
initramfs 2016-08-05 09:20:21 +08:00
parent 07f5cf3a65
commit f6a698bec5
No known key found for this signature in database
GPG Key ID: 78B8BDF87E9EF0AF
2 changed files with 210 additions and 181 deletions

View File

@ -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);

View File

@ -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