Wavelength
Privacy-focused, cross-platform, and open-source communication application
Loading...
Searching...
No Matches
GifDecoder Class Referencefinal

Decodes GIF data frame by frame using FFmpeg libraries in a separate thread. More...

#include <gif_decoder.h>

Inheritance diagram for GifDecoder:
Collaboration diagram for GifDecoder:

Signals

void error (const QString &message)
 Emitted when an error occurs during initialization or decoding.
 
void firstFrameReady (const QImage &frame)
 Emitted once after successful initialization, containing the first frame. Useful for displaying a static preview before the animation starts.
 
void frameReady (const QImage &frame)
 Emitted for each decoded frame of the GIF.
 
void gifInfo (int width, int height, double duration, double frame_rate, int num_of_streams)
 Emitted after successful initialization, providing GIF stream details.
 
void playbackFinished ()
 Emitted when the decoder reaches the end of the stream (before looping).
 
void positionChanged (double position)
 Emitted periodically during playback to indicate the current position.
 

Public Member Functions

double GetDuration () const
 Gets the total duration of the GIF in seconds, if available. Reads the duration from the FFmpeg format context.
 
 GifDecoder (const QByteArray &gif_data, QObject *parent=nullptr)
 Constructs a GifDecoder object. Initializes internal state, allocates memory for FFmpeg's custom I/O context, and copies the provided GIF data into an internal buffer.
 
bool Initialize ()
 Initializes the FFmpeg components for decoding the GIF. Opens the input stream using the custom I/O context, finds the GIF stream and codec, opens the codec, sets up the scaler (to convert to RGBA), allocates frames and buffers. Emits gifInfo and firstFrameReady upon success. This operation is thread-safe and should be called before starting the thread.
 
bool IsDecoderRunning () const
 Checks if the decoding thread is currently running.
 
bool IsPaused () const
 Checks if the decoding is currently paused. This operation is thread-safe.
 
void Pause ()
 Pauses the decoding loop. Sets the paused_ flag. The thread will wait on the wait_condition_ in its next iteration. This operation is thread-safe.
 
bool Reinitialize ()
 Reinitializes the decoder after it has been stopped or encountered an error. Stops the thread if running, releases existing FFmpeg resources, resets state flags (paused, stopped, position), and reallocates I/O context if necessary. Does not automatically start playback. This operation is thread-safe.
 
void ReleaseResources ()
 Releases all FFmpeg resources (contexts, frames, buffers). Does not release the custom I/O context buffer, as that's handled separately. Resets the initialization flag. This operation is thread-safe.
 
void Reset ()
 Resets the playback position to the beginning of the GIF. Seeks the FFmpeg format context to the start, flushes codec buffers, resets the internal position counter, and emits positionChanged(0). This operation is thread-safe.
 
void Resume ()
 Resumes decoding if paused or starts the thread if not already running. Clears the paused_ flag and wakes the thread if it's waiting. If the thread hasn't been started yet, it calls start(). This operation is thread-safe.
 
void Stop ()
 Stops the decoding thread gracefully. Sets the stopped_ flag, unpauses if necessary, and wakes the thread if it's waiting. The thread will then exit its run loop. This operation is thread-safe.
 
 ~GifDecoder () override
 Destructor. Stops the decoding thread, waits for it to finish, and releases all allocated resources.
 

Protected Member Functions

void run () override
 The main function executed by the QThread. Contains the loop that reads packets, decodes frames, handles pausing/looping, calculates frame delays, and emits decoded frames via the frameReady signal.
 

Private Member Functions

void ExtractAndEmitFirstFrameInternal ()
 Internal helper function called by Initialize() to extract and emit the first frame. Seeks to the beginning, decodes frames until the first one is successfully obtained, emits it via firstFrameReady, and then seeks back to the beginning for the main run() loop.
 

Static Private Member Functions

static int ReadPacket (void *opaque, uint8_t *buf, int buf_size)
 Custom read function for FFmpeg's AVIOContext. Reads data from the internal gif_data_ QByteArray buffer.
 
static int64_t SeekPacket (void *opaque, int64_t offset, int whence)
 Custom seek function for FFmpeg's AVIOContext. Adjusts the internal read_position_ based on the offset and whence parameters. Supports SEEK_SET, SEEK_CUR, SEEK_END, and AVSEEK_SIZE.
 

Private Attributes

uint8_t * buffer_ = nullptr
 Buffer holding the pixel data for frame_rgb_.
 
int buffer_size_ = 0
 Size of the buffer_ in bytes.
 
AVCodecContext * codec_context_ = nullptr
 FFmpeg context for the GIF codec.
 
double current_position_ = 0
 Current playback position in seconds. Access protected by mutex_.
 
AVFormatContext * format_context_ = nullptr
 FFmpeg context for handling the container format (GIF).
 
AVFrame * frame_ = nullptr
 FFmpeg frame structure to hold the raw decoded frame data.
 
double frame_delay_ = 100.0
 Calculated delay between frames in milliseconds.
 
double frame_rate_ = 0.0
 Calculated average frame rate of the GIF in frames per second.
 
AVFrame * frame_rgb_ = nullptr
 FFmpeg frame structure to hold the frame data after conversion to RGBA.
 
QElapsedTimer frame_timer_
 Timer used to help synchronize frame emission based on frame_delay_.
 
QByteArray gif_data_
 The raw GIF data provided in the constructor.
 
int gif_stream_ = -1
 Index of the video stream within the format context.
 
bool initialized_ = false
 Flag indicating if the Initialize() method has completed successfully. Access protected by mutex_.
 
unsigned char * io_buffer_ = nullptr
 Buffer used by the custom I/O context to hold gif_data_.
 
AVIOContext * io_context_ = nullptr
 FFmpeg context for custom I/O operations (reading from memory).
 
QMutex mutex_
 Mutex protecting access to shared state variables from different threads.
 
bool paused_ = true
 Flag indicating if playback is currently paused. Access protected by mutex_.
 
bool reached_end_of_stream_ = false
 Flag indicating if the end of the GIF stream has been reached (before looping). Access protected by mutex_.
 
int read_position_ = 0
 Current read position within gif_data_ for the custom I/O context.
 
int64_t seek_position_ = 0
 Target timestamp for the pending seek operation (in stream timebase). Access protected by mutex_.
 
bool stopped_ = false
 Flag indicating if the thread should stop execution. Access protected by mutex_.
 
SwsContext * sws_context_ = nullptr
 FFmpeg context for image scaling and pixel format conversion (to RGBA).
 
QWaitCondition wait_condition_
 Condition variable used to pause/resume the decoding thread.
 

Detailed Description

Decodes GIF data frame by frame using FFmpeg libraries in a separate thread.

This class takes raw GIF data as a QByteArray, uses FFmpeg (libavformat, libavcodec, libswscale) to decode it frame by frame, and emits each decoded frame as a QImage (Format_RGBA8888). It runs the decoding loop in a separate QThread to avoid blocking the main UI thread. It supports pausing, resuming, looping, and provides signals for status updates (errors, info, position, frames). It uses a custom AVIOContext to read data directly from the QByteArray in memory.

Constructor & Destructor Documentation

◆ GifDecoder()

GifDecoder::GifDecoder ( const QByteArray & gif_data,
QObject * parent = nullptr )
explicit

Constructs a GifDecoder object. Initializes internal state, allocates memory for FFmpeg's custom I/O context, and copies the provided GIF data into an internal buffer.

Parameters
gif_dataThe raw GIF data to be decoded.
parentOptional parent QObject.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ~GifDecoder()

GifDecoder::~GifDecoder ( )
override

Destructor. Stops the decoding thread, waits for it to finish, and releases all allocated resources.

Here is the call graph for this function:

Member Function Documentation

◆ error

void GifDecoder::error ( const QString & message)
signal

Emitted when an error occurs during initialization or decoding.

Parameters
messageA description of the error.
Here is the caller graph for this function:

◆ ExtractAndEmitFirstFrameInternal()

void GifDecoder::ExtractAndEmitFirstFrameInternal ( )
private

Internal helper function called by Initialize() to extract and emit the first frame. Seeks to the beginning, decodes frames until the first one is successfully obtained, emits it via firstFrameReady, and then seeks back to the beginning for the main run() loop.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ firstFrameReady

void GifDecoder::firstFrameReady ( const QImage & frame)
signal

Emitted once after successful initialization, containing the first frame. Useful for displaying a static preview before the animation starts.

Parameters
frameThe first decoded frame as a QImage (Format_RGBA8888). A copy is emitted.
Here is the caller graph for this function:

◆ frameReady

void GifDecoder::frameReady ( const QImage & frame)
signal

Emitted for each decoded frame of the GIF.

Parameters
frameThe decoded frame as a QImage (Format_RGBA8888). A copy is emitted.
Here is the caller graph for this function:

◆ GetDuration()

double GifDecoder::GetDuration ( ) const
inline

Gets the total duration of the GIF in seconds, if available. Reads the duration from the FFmpeg format context.

Returns
The duration in seconds, or 0.0 if not available.

◆ gifInfo

void GifDecoder::gifInfo ( int width,
int height,
double duration,
double frame_rate,
int num_of_streams )
signal

Emitted after successful initialization, providing GIF stream details.

Parameters
widthThe width of the GIF in pixels.
heightThe height of the GIF in pixels.
durationThe total duration of the GIF in seconds (can be approximate).
frame_rateThe calculated average frame rate in frames per second.
num_of_streamsThe number of streams found (should typically be 1 for GIF).
Here is the caller graph for this function:

◆ Initialize()

bool GifDecoder::Initialize ( )

Initializes the FFmpeg components for decoding the GIF. Opens the input stream using the custom I/O context, finds the GIF stream and codec, opens the codec, sets up the scaler (to convert to RGBA), allocates frames and buffers. Emits gifInfo and firstFrameReady upon success. This operation is thread-safe and should be called before starting the thread.

Returns
True if initialization was successful, false otherwise.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsDecoderRunning()

bool GifDecoder::IsDecoderRunning ( ) const
inline

Checks if the decoding thread is currently running.

Returns
True if the thread is running, false otherwise.
Here is the caller graph for this function:

◆ IsPaused()

bool GifDecoder::IsPaused ( ) const
inline

Checks if the decoding is currently paused. This operation is thread-safe.

Returns
True if paused, false otherwise.

◆ Pause()

void GifDecoder::Pause ( )

Pauses the decoding loop. Sets the paused_ flag. The thread will wait on the wait_condition_ in its next iteration. This operation is thread-safe.

◆ playbackFinished

void GifDecoder::playbackFinished ( )
signal

Emitted when the decoder reaches the end of the stream (before looping).

Deprecated
This signal is not emitted, but wasn't remove as part of legacy code cleanup. Note: Currently not emitted as the decoder loops indefinitely.

◆ positionChanged

void GifDecoder::positionChanged ( double position)
signal

Emitted periodically during playback to indicate the current position.

Parameters
positionThe current playback position in seconds.
Here is the caller graph for this function:

◆ ReadPacket()

int GifDecoder::ReadPacket ( void * opaque,
uint8_t * buf,
int buf_size )
staticprivate

Custom read function for FFmpeg's AVIOContext. Reads data from the internal gif_data_ QByteArray buffer.

Parameters
opaquePointer to the GifDecoder instance.
bufBuffer to read data into.
buf_sizeSize of the buffer.
Returns
Number of bytes read, or AVERROR_EOF if the end of data is reached.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Reinitialize()

bool GifDecoder::Reinitialize ( )

Reinitializes the decoder after it has been stopped or encountered an error. Stops the thread if running, releases existing FFmpeg resources, resets state flags (paused, stopped, position), and reallocates I/O context if necessary. Does not automatically start playback. This operation is thread-safe.

Returns
True if reinitialization setup was successful, false otherwise.
Here is the call graph for this function:

◆ ReleaseResources()

void GifDecoder::ReleaseResources ( )

Releases all FFmpeg resources (contexts, frames, buffers). Does not release the custom I/O context buffer, as that's handled separately. Resets the initialization flag. This operation is thread-safe.

Here is the caller graph for this function:

◆ Reset()

void GifDecoder::Reset ( )

Resets the playback position to the beginning of the GIF. Seeks the FFmpeg format context to the start, flushes codec buffers, resets the internal position counter, and emits positionChanged(0). This operation is thread-safe.

Here is the call graph for this function:

◆ Resume()

void GifDecoder::Resume ( )

Resumes decoding if paused or starts the thread if not already running. Clears the paused_ flag and wakes the thread if it's waiting. If the thread hasn't been started yet, it calls start(). This operation is thread-safe.

Here is the call graph for this function:

◆ run()

void GifDecoder::run ( )
overrideprotected

The main function executed by the QThread. Contains the loop that reads packets, decodes frames, handles pausing/looping, calculates frame delays, and emits decoded frames via the frameReady signal.

Here is the call graph for this function:

◆ SeekPacket()

int64_t GifDecoder::SeekPacket ( void * opaque,
int64_t offset,
int whence )
staticprivate

Custom seek function for FFmpeg's AVIOContext. Adjusts the internal read_position_ based on the offset and whence parameters. Supports SEEK_SET, SEEK_CUR, SEEK_END, and AVSEEK_SIZE.

Parameters
opaquePointer to the GifDecoder instance.
offsetThe offset to seek to/by.
whenceThe seeking mode (SEEK_SET, SEEK_CUR, SEEK_END, AVSEEK_SIZE).
Returns
The new read position, or the total size if whence is AVSEEK_SIZE, or -1 on error.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Stop()

void GifDecoder::Stop ( )

Stops the decoding thread gracefully. Sets the stopped_ flag, unpauses if necessary, and wakes the thread if it's waiting. The thread will then exit its run loop. This operation is thread-safe.

Here is the caller graph for this function:

Member Data Documentation

◆ buffer_

uint8_t* GifDecoder::buffer_ = nullptr
private

Buffer holding the pixel data for frame_rgb_.

◆ buffer_size_

int GifDecoder::buffer_size_ = 0
private

Size of the buffer_ in bytes.

◆ codec_context_

AVCodecContext* GifDecoder::codec_context_ = nullptr
private

FFmpeg context for the GIF codec.

◆ current_position_

double GifDecoder::current_position_ = 0
private

Current playback position in seconds. Access protected by mutex_.

◆ format_context_

AVFormatContext* GifDecoder::format_context_ = nullptr
private

FFmpeg context for handling the container format (GIF).

◆ frame_

AVFrame* GifDecoder::frame_ = nullptr
private

FFmpeg frame structure to hold the raw decoded frame data.

◆ frame_delay_

double GifDecoder::frame_delay_ = 100.0
private

Calculated delay between frames in milliseconds.

◆ frame_rate_

double GifDecoder::frame_rate_ = 0.0
private

Calculated average frame rate of the GIF in frames per second.

◆ frame_rgb_

AVFrame* GifDecoder::frame_rgb_ = nullptr
private

FFmpeg frame structure to hold the frame data after conversion to RGBA.

◆ frame_timer_

QElapsedTimer GifDecoder::frame_timer_
private

Timer used to help synchronize frame emission based on frame_delay_.

◆ gif_data_

QByteArray GifDecoder::gif_data_
private

The raw GIF data provided in the constructor.

◆ gif_stream_

int GifDecoder::gif_stream_ = -1
private

Index of the video stream within the format context.

◆ initialized_

bool GifDecoder::initialized_ = false
private

Flag indicating if the Initialize() method has completed successfully. Access protected by mutex_.

◆ io_buffer_

unsigned char* GifDecoder::io_buffer_ = nullptr
private

Buffer used by the custom I/O context to hold gif_data_.

◆ io_context_

AVIOContext* GifDecoder::io_context_ = nullptr
private

FFmpeg context for custom I/O operations (reading from memory).

◆ mutex_

QMutex GifDecoder::mutex_
mutableprivate

Mutex protecting access to shared state variables from different threads.

◆ paused_

bool GifDecoder::paused_ = true
private

Flag indicating if playback is currently paused. Access protected by mutex_.

◆ reached_end_of_stream_

bool GifDecoder::reached_end_of_stream_ = false
private

Flag indicating if the end of the GIF stream has been reached (before looping). Access protected by mutex_.

◆ read_position_

int GifDecoder::read_position_ = 0
private

Current read position within gif_data_ for the custom I/O context.

◆ seek_position_

int64_t GifDecoder::seek_position_ = 0
private

Target timestamp for the pending seek operation (in stream timebase). Access protected by mutex_.

◆ stopped_

bool GifDecoder::stopped_ = false
private

Flag indicating if the thread should stop execution. Access protected by mutex_.

◆ sws_context_

SwsContext* GifDecoder::sws_context_ = nullptr
private

FFmpeg context for image scaling and pixel format conversion (to RGBA).

◆ wait_condition_

QWaitCondition GifDecoder::wait_condition_
private

Condition variable used to pause/resume the decoding thread.


The documentation for this class was generated from the following files: