Files
gdmp/ff_ffplay_def.h

260 lines
9.9 KiB
C
Raw Permalink Normal View History

2025-09-25 16:56:53 +08:00
#ifndef FF_FFPLAY_DEF_H
#define FF_FFPLAY_DEF_H
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
extern "C" {
#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
}
#include <SDL.h>
#include <SDL_thread.h>
#include <assert.h>
#include "ijksdl_timer.h"
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_FRAMES 25
#define EXTERNAL_CLOCK_MIN_FRAMES 2
#define EXTERNAL_CLOCK_MAX_FRAMES 10
/* Step size for volume control in dB */
#define SDL_VOLUME_STEP (0.75)
/* no AV sync correction is done if below the minimum AV sync threshold */
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
#define AV_SYNC_THRESHOLD_MAX 0.1
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0
typedef struct FFTrackCacheStatistic
{
int64_t duration;
int64_t bytes;
int64_t packets;
} FFTrackCacheStatistic;
typedef struct FFStatistic
{
int64_t vdec_type;
float vfps;
float vdps;
float avdelay;
float avdiff;
int64_t bit_rate;
FFTrackCacheStatistic video_cache;
FFTrackCacheStatistic audio_cache;
int64_t buf_backwards;
int64_t buf_forwards;
int64_t buf_capacity;
SDL_SpeedSampler2 tcp_read_sampler;
int64_t latest_seek_load_duration;
int64_t byte_count;
int64_t cache_physical_pos;
int64_t cache_file_forwards;
int64_t cache_file_pos;
int64_t cache_count_bytes;
int64_t logical_file_size;
int drop_frame_count;
int decode_frame_count;
float drop_frame_rate;
} FFStatistic;
enum RET_CODE
{
RET_ERR_UNKNOWN = -2, // 未知错误
RET_FAIL = -1, // 失败
RET_OK = 0, // 正常
RET_ERR_OPEN_FILE, // 打开文件失败
RET_ERR_NOT_SUPPORT, // 不支持
RET_ERR_OUTOFMEMORY, // 没有内存
RET_ERR_STACKOVERFLOW, // 溢出
RET_ERR_NULLREFERENCE, // 空参考
RET_ERR_ARGUMENTOUTOFRANGE, //
RET_ERR_PARAMISMATCH, //
RET_ERR_MISMATCH_CODE, // 没有匹配的编解码器
RET_ERR_EAGAIN,
RET_ERR_EOF
};
typedef struct MyAVPacketList {
AVPacket pkt; //解封装后的数据
struct MyAVPacketList *next; //下一个节点
int serial; //播放序列
} MyAVPacketList;
typedef struct PacketQueue {
MyAVPacketList *first_pkt, *last_pkt; // 队首,队尾指针
int nb_packets; // 包数量,也就是队列元素数量
int size; // 队列所有元素的数据大小总和
int64_t duration; // 队列所有元素的数据播放持续时间
int abort_request; // 用户退出请求标志
int serial; // 播放序列号和MyAVPacketList的serial作用相同但改变的时序稍微有点不同
SDL_mutex *mutex; // 用于维持PacketQueue的多线程安全(SDL_mutex可以按pthread_mutex_t理解
SDL_cond *cond; // 用于读、写线程相互通知(SDL_cond可以按pthread_cond_t理解)
} PacketQueue;
#define VIDEO_PICTURE_QUEUE_SIZE 3 // 图像帧缓存数量
#define VIDEO_PICTURE_QUEUE_SIZE_MIN (3)
#define VIDEO_PICTURE_QUEUE_SIZE_MAX (16)
#define VIDEO_PICTURE_QUEUE_SIZE_DEFAULT (VIDEO_PICTURE_QUEUE_SIZE_MIN)
#define SUBPICTURE_QUEUE_SIZE 16 // 字幕帧缓存数量
#define SAMPLE_QUEUE_SIZE 9 // 采样帧缓存数量
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
typedef struct AudioParams {
int freq; // 采样率
int channels; // 通道数
int64_t channel_layout; // 通道布局比如2.1声道5.1声道等
enum AVSampleFormat fmt; // 音频采样格式比如AV_SAMPLE_FMT_S16表示为有符号16bit深度交错排列模式。
int frame_size; // 一个采样单元占用的字节数比如2通道时则左右通道各采样一次合成一个采样单元
int bytes_per_sec; // 一秒时间的字节数比如采样率48Khz2 channel16bit则一秒48000*2*16/8=192000
} AudioParams;
/* Common struct for handling all types of decoded data and allocated render buffers. */
// 用于缓存解码后的数据
typedef struct Frame {
AVFrame *frame; // 指向数据帧
int serial; // 帧序列在seek的操作时serial会变化
double pts; // 时间戳,单位为秒
double duration; // 该帧持续时间,单位为秒
int64_t pos;
int width; // 图像宽度
int height; // 图像高读
int format; // 对于图像为(enum AVPixelFormat)
AVRational sar;
int uploaded;
int flip_v;
} Frame;
/* 这是一个循环队列windex是指其中的首元素rindex是指其中的尾部元素. */
typedef struct FrameQueue {
Frame queue[FRAME_QUEUE_SIZE]; // FRAME_QUEUE_SIZE 最大size, 数字太大时会占用大量的内存,需要注意该值的设置
int rindex; // 读索引。待播放时读取此帧进行播放,播放后此帧成为上一帧
int windex; // 写索引
int size; // 当前总帧数
int max_size; // 可存储最大帧数
int keep_last;
int rindex_shown;
SDL_mutex *mutex; // 互斥量
SDL_cond *cond; // 条件变量
PacketQueue *pktq; // 数据包缓冲队列
} FrameQueue;
// 这里讲的系统时钟 是通过av_gettime_relative()获取到的时钟,单位为微妙
typedef struct Clock {
double pts; // 时钟基础, 当前帧(待播放)显示时间戳,播放后,当前帧变成上一帧
// 当前pts与当前系统时钟的差值, audio、video对于该值是独立的
double pts_drift; // clock base minus time at which we updated the clock
// 当前时钟(如视频时钟)最后一次更新时间,也可称当前时钟时间
double last_updated; // 最后一次更新的系统时钟
double speed; // 时钟速度控制,用于控制播放速度
// 播放序列所谓播放序列就是一段连续的播放动作一个seek操作会启动一段新的播放序列
int serial; // clock is based on a packet with this serial
int paused; // = 1 说明是暂停状态
// 指向packet_serial
int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;
/**
*
*/
enum {
AV_SYNC_UNKNOW_MASTER = -1,
AV_SYNC_AUDIO_MASTER, // 以音频为基准
AV_SYNC_VIDEO_MASTER, // 以视频为基准
// AV_SYNC_EXTERNAL_CLOCK, // 以外部时钟为基准synchronize to an external clock */
};
#define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE))
#define milliseconds_to_fftime(ms) (av_rescale(ms, AV_TIME_BASE, 1000))
extern AVPacket flush_pkt;
// 队列相关
int packet_queue_put(PacketQueue *q, AVPacket *pkt);
int packet_queue_put_nullpacket(PacketQueue *q, int stream_index);
int packet_queue_init(PacketQueue *q);
void packet_queue_flush(PacketQueue *q);
void packet_queue_destroy(PacketQueue *q);
void packet_queue_abort(PacketQueue *q);
void packet_queue_start(PacketQueue *q);
int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial);
/**
* @brief
* @param q
* @param time_base packet的时间戳转换
* @param packet_duration
* @return
*/
double packet_queue_cache_duration(PacketQueue *q, AVRational time_base, double packet_duration);
/* 初始化FrameQueue视频和音频keep_last设置为1字幕设置为0 */
int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last);
void frame_queue_destory(FrameQueue *f);
void frame_queue_signal(FrameQueue *f);
/* 获取队列当前Frame, 在调用该函数前先调用frame_queue_nb_remaining确保有frame可读 */
Frame *frame_queue_peek(FrameQueue *f);
/* 获取当前Frame的下一Frame, 此时要确保queue里面至少有2个Frame */
// 不管你什么时候调用,返回来肯定不是 NULL
Frame *frame_queue_peek_next(FrameQueue *f);
/* 获取last Frame
*/
Frame *frame_queue_peek_last(FrameQueue *f);
// 获取可写指针
Frame *frame_queue_peek_writable(FrameQueue *f);
// 获取可读
Frame *frame_queue_peek_readable(FrameQueue *f);
// 更新写指针
void frame_queue_push(FrameQueue *f);
/* 释放当前frame并更新读索引rindex */
void frame_queue_next(FrameQueue *f);
int frame_queue_nb_remaining(FrameQueue *f);
int64_t frame_queue_last_pos(FrameQueue *f);
// 时钟相关
double get_clock(Clock *c);
void set_clock_at(Clock *c, double pts, int serial, double time);
void set_clock(Clock *c, double pts, int serial);
void init_clock(Clock *c, int *queue_serial);
void ffp_reset_statistic(FFStatistic *dcc);
#endif // FF_FFPLAY_DEF_H