|
Wavelength
Privacy-focused, cross-platform, and open-source communication application
|
Decodes GIF data frame by frame using FFmpeg libraries in a separate thread. More...
#include <gif_decoder.h>
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. | |
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.
|
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.
| gif_data | The raw GIF data to be decoded. |
| parent | Optional parent QObject. |
|
override |
Destructor. Stops the decoding thread, waits for it to finish, and releases all allocated resources.
|
signal |
Emitted when an error occurs during initialization or decoding.
| message | A description of the error. |
|
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.
|
signal |
Emitted once after successful initialization, containing the first frame. Useful for displaying a static preview before the animation starts.
| frame | The first decoded frame as a QImage (Format_RGBA8888). A copy is emitted. |
|
signal |
Emitted for each decoded frame of the GIF.
| frame | The decoded frame as a QImage (Format_RGBA8888). A copy is emitted. |
|
inline |
Gets the total duration of the GIF in seconds, if available. Reads the duration from the FFmpeg format context.
|
signal |
Emitted after successful initialization, providing GIF stream details.
| width | The width of the GIF in pixels. |
| height | The height of the GIF in pixels. |
| duration | The total duration of the GIF in seconds (can be approximate). |
| frame_rate | The calculated average frame rate in frames per second. |
| num_of_streams | The number of streams found (should typically be 1 for GIF). |
| 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.
|
inline |
Checks if the decoding thread is currently running.
|
inline |
Checks if the decoding is currently paused. This operation is thread-safe.
| 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.
|
signal |
Emitted when the decoder reaches the end of the stream (before looping).
|
signal |
Emitted periodically during playback to indicate the current position.
| position | The current playback position in seconds. |
|
staticprivate |
Custom read function for FFmpeg's AVIOContext. Reads data from the internal gif_data_ QByteArray buffer.
| opaque | Pointer to the GifDecoder instance. |
| buf | Buffer to read data into. |
| buf_size | Size of the buffer. |
| 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.
| 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.
| 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.
| 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.
|
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.
|
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.
| opaque | Pointer to the GifDecoder instance. |
| offset | The offset to seek to/by. |
| whence | The seeking mode (SEEK_SET, SEEK_CUR, SEEK_END, AVSEEK_SIZE). |
| 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.
|
private |
Buffer holding the pixel data for frame_rgb_.
|
private |
Size of the buffer_ in bytes.
|
private |
FFmpeg context for the GIF codec.
|
private |
Current playback position in seconds. Access protected by mutex_.
|
private |
FFmpeg context for handling the container format (GIF).
|
private |
FFmpeg frame structure to hold the raw decoded frame data.
|
private |
Calculated delay between frames in milliseconds.
|
private |
Calculated average frame rate of the GIF in frames per second.
|
private |
FFmpeg frame structure to hold the frame data after conversion to RGBA.
|
private |
Timer used to help synchronize frame emission based on frame_delay_.
|
private |
The raw GIF data provided in the constructor.
|
private |
Index of the video stream within the format context.
|
private |
Flag indicating if the Initialize() method has completed successfully. Access protected by mutex_.
|
private |
Buffer used by the custom I/O context to hold gif_data_.
|
private |
FFmpeg context for custom I/O operations (reading from memory).
|
mutableprivate |
Mutex protecting access to shared state variables from different threads.
|
private |
Flag indicating if playback is currently paused. Access protected by mutex_.
|
private |
Flag indicating if the end of the GIF stream has been reached (before looping). Access protected by mutex_.
|
private |
Current read position within gif_data_ for the custom I/O context.
|
private |
Target timestamp for the pending seek operation (in stream timebase). Access protected by mutex_.
|
private |
Flag indicating if the thread should stop execution. Access protected by mutex_.
|
private |
FFmpeg context for image scaling and pixel format conversion (to RGBA).
|
private |
Condition variable used to pause/resume the decoding thread.