ffplay源码分析(二)stream_open

本文详细介绍了FFplay中的stream_open函数,其主要负责初始化播放器上下文、队列和线程,包括VideoState结构的创建、帧缓存、包缓存队列设置,以及关键组件的初始化过程。
摘要由CSDN通过智能技术生成

stream_open主要流程

在这里插入图片描述
stream_open 流程主要负责播放器运行过程中相关上下文和队列的初始化,以及码流读取线程的创建。
也就是从这个函数开始,播放器就真正开始运行起来了。
本次主要还是介绍这个过程中使用到的结构体。
比较重要的后面单独解析。

stream_open源码

static VideoState *stream_open(const char *filename,
                               const AVInputFormat *iformat)
{
    //创建VideoState结构体,这个结构体是ffplay的核心上下文,贯穿整个播放流程
    VideoState *is;
    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
    //初始化is,保存filename和iformat
    is->last_video_stream = is->video_stream = -1;
    is->last_audio_stream = is->audio_stream = -1;
    is->last_subtitle_stream = is->subtitle_stream = -1;
    is->filename = av_strdup(filename);
    if (!is->filename)
        goto fail;
    is->iformat = iformat;
    is->ytop    = 0;
    is->xleft   = 0;

    /*初始化帧缓存队列,视频初始化,大小如下
      VIDEO_PICTURE_QUEUE_SIZE 3
      SUBPICTURE_QUEUE_SIZE 16
      SAMPLE_QUEUE_SIZE 9 */
    if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
        goto fail;
    if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
        goto fail;
    if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
        goto fail;

    /*
      初始化包缓存队列
    */
    if (packet_queue_init(&is->videoq) < 0 ||
        packet_queue_init(&is->audioq) < 0 ||
        packet_queue_init(&is->subtitleq) < 0)
        goto fail;
    // 创建SDL条件变量,这个条件变量用于read_thread线程,为了防止没有数据时线程空转。
    if (!(is->continue_read_thread = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        goto fail;
    }
    //创建音频、视频、外部时钟
    init_clock(&is->vidclk, &is->videoq.serial);
    init_clock(&is->audclk, &is->audioq.serial);
    init_clock(&is->extclk, &is->extclk.serial);
    is->audio_clock_serial = -1;
    if (startup_volume < 0)
        av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", startup_volume);
    if (startup_volume > 100)
        av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", startup_volume);
    startup_volume = av_clip(startup_volume, 0, 100);
    startup_volume = av_clip(SDL_MIX_MAXVOLUME * startup_volume / 100, 0, SDL_MIX_MAXVOLUME);
    is->audio_volume = startup_volume;
    is->muted = 0;
    is->av_sync_type = av_sync_type;
    //创建收包线程
    is->read_tid     = SDL_CreateThread(read_thread, "read_thread", is);
    if (!is->read_tid) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
fail:
        stream_close(is);
        return NULL;
    }
    return is;
}

VideoStatu结构体

typedef struct VideoState {
    SDL_Thread *read_tid;  			      
    const AVInputFormat *iformat;//ffmpeg输入格式
    int abort_request; //stream停止请求     
    int force_refresh; //强制刷新
    int paused;//暂停
    int last_paused;//上一次暂停状态,播放器的开始和暂停状态由内部控制,即调用者不用关心本次调的是开始还是暂停
    int queue_attachments_req;//缩略图请求
    //seek相关,后续会详细讲解
    int seek_req;
    int seek_flags;
    int64_t seek_pos;
    int64_t seek_rel;
    int read_pause_return; //网络中的暂停消息
    AVFormatContext *ic;//ffmpeg核心上下文
    int realtime;//是否实时(缓存策略等处理不同)

	//音视频同步相关,后续会详细讲解
    Clock audclk;
    Clock vidclk;
    Clock extclk;

   //Frame数据缓存
    FrameQueue pictq;
    FrameQueue subpq;
    FrameQueue sampq;

	//解码器
    Decoder auddec;
    Decoder viddec;
    Decoder subdec;
    
    int audio_stream;//音频流id

    int av_sync_type;//音视频同步方式

    double audio_clock;//音频时钟,根据pts计算
    int audio_clock_serial;//音频序列号,跳转后会更新
    //用于音频同步视频的情况
    double audio_diff_cum; /* used for AV difference average computation */
    double audio_diff_avg_coef;
    double audio_diff_threshold;
    int audio_diff_avg_count;
    

    AVStream *audio_st; //音频流结构体
    PacketQueue audioq;//音频队列
    int audio_hw_buf_size;//音频硬件缓存buffer大小
    //音频播放Ringbuffer
    uint8_t *audio_buf;
    //临时buffer
    uint8_t *audio_buf1;
    unsigned int audio_buf_size; /* in bytes */
    unsigned int audio_buf1_size;
    int audio_buf_index; /* in bytes */
    int audio_write_buf_size;

    int audio_volume;//音量
    int muted;//静音标识
    //音频转码相关
    struct AudioParams audio_src;
    struct AudioParams audio_filter_src;
    struct AudioParams audio_tgt;
    struct SwrContext *swr_ctx;
    //丢帧统计
    int frame_drops_early;
    int frame_drops_late;

    enum ShowMode {
        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
    } show_mode;
    int16_t sample_array[SAMPLE_ARRAY_SIZE];//音频样本
    int sample_array_index;
    //音频波形显示相关
    int last_i_start;
    AVTXContext *rdft;
    av_tx_fn rdft_fn;
    int rdft_bits;
    float *real_data;
    AVComplexFloat *rdft_data;
    int xpos;
    double last_vis_time;
    SDL_Texture *vis_texture;
   
    SDL_Texture *sub_texture; //字幕显示纹理
    SDL_Texture *vid_texture; //视频显示纹理
 
    int subtitle_stream; //字幕流id
    AVStream *subtitle_st;//字幕流
    PacketQueue subtitleq;//字幕队列

    double frame_timer;//视频当前播放时间
    double frame_last_returned_time;
    double frame_last_filter_delay;
    int video_stream;//视频流id
    AVStream *video_st; //视频流
    PacketQueue videoq;//视频流队列
    double max_frame_duration;      //最大帧间隔,如果超过将会丢弃数据
    struct SwsContext *sub_convert_ctx;
    int eof;

    char *filename;
    int width, height, xleft, ytop;
    int step;

    int vfilter_idx;
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
    AVFilterContext *in_audio_filter;   // the first filter in the audio chain
    AVFilterContext *out_audio_filter;  // the last filter in the audio chain
    AVFilterGraph *agraph;              // audio filter graph

    int last_video_stream, last_audio_stream, last_subtitle_stream;

    SDL_cond *continue_read_thread;//读数据线程条件变量
} VideoState;

系列文章目录

ffplay源码分析(一)主函数
未完待续…

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值