Files
gdmp/ff_ffplay_def.h
2025-09-25 16:56:53 +08:00

260 lines
9.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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