ffmpeg+QT player

一、项目分析
在这里插入图片描述
二、界面设计
在这里插入图片描述
选定widgets模板
在这里插入图片描述
选择forms文件,设计界面

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
导入icon图标
在这里插入图片描述
编译界面效果如下图:
在这里插入图片描述

播放器代码逻辑:
在这里插入图片描述
在这里插入图片描述
打通ui到播放器核心的通道
1.消息队列
ffmsg.h

#ifndef FFMSG_QUEUE_H
#define FFMSG_QUEUE_H
#include "SDL.h"

typedef struct AVMessage {
    int what;           // 消息类型
    int arg1;           // 参数1
    int arg2;           // 参数2
    void *obj;          // 如果arg1 arg2还不够存储消息则使⽤该参数
    void (*free_l)(void *obj);  // obj的对象是分配的,这⾥要给出函数怎么释放
    struct AVMessage *next; // 下⼀个消息
} AVMessage;


typedef struct MessageQueue {   // 消息队列
    AVMessage *first_msg, *last_msg;    // 消息头,消息尾部
    int nb_messages;    // 有多少个消息
    int abort_request;  // 请求终止消息队列
    SDL_mutex *mutex;   // 互斥量
    SDL_cond *cond;     // 条件变量,用于等待线程
    AVMessage *recycle_msg; // 消息循环使用
    int recycle_count;  // 循环的次数,利用局部性原理
    int alloc_count;    // 分配的次数
} MessageQueue;

// 写api,程序之间的接口
// 释放msg的obj资源
void msg_free_res(AVMessage *msg);
// 私有插⼊消息
int msg_queue_put_private(MessageQueue *q, AVMessage *msg);
//插⼊消息
int msg_queue_put(MessageQueue *q, AVMessage *msg);
// 初始化消息
void msg_init_msg(AVMessage *msg);
// 插⼊简单消息,只带消息类型,不带参数
void msg_queue_put_simple1(MessageQueue *q, int what);
// 插⼊简单消息,只带消息类型,只带1个参数
void msg_queue_put_simple2(MessageQueue *q, int what, int arg1);
// 插⼊简单消息,只带消息类型,带2个参数
void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2);
// 释放msg的obj资源
void msg_obj_free_l(void *obj);
//插⼊消息,带消息类型,带2个参数,带obj
void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len);
// 消息队列初始化
void msg_queue_init(MessageQueue *q);
// 消息队列flush,清空所有的消息
void msg_queue_flush(MessageQueue *q);
// 消息销毁
void msg_queue_destroy(MessageQueue *q);
// 消息队列终⽌
void msg_queue_abort(MessageQueue *q);
// 启⽤消息队列
void msg_queue_start(MessageQueue *q);
// 读取消息
/* return < 0 if aborted, 0 if no msg and > 0 if msg. */
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block);
// 消息删除 把队列⾥同⼀消息类型的消息全删除掉
void msg_queue_remove(MessageQueue *q, int what);

#endif // FFMSG_QUEUE_H

ffmsg.cpp

#include "ffmsg_queue.h"
#include "ffmsg.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"
}

// 释放msg的obj资源
void msg_free_res(AVMessage *msg)
{
    if(!msg || msg->obj)
        return;
    msg->free_l(msg->obj);// obj的对象是分配的,这⾥要给出函数怎么释放
    msg->obj = NULL;
}

//消息队列内部重新去构建AVMessage(重新申请AVMessage,或者来自于recyc_meg)
//新的消息插入到尾部
int msg_queue_put_private(MessageQueue *q, AVMessage *msg)
{
    AVMessage *msg1;
    if(q->abort_request)// 请求终止消息队列
        return -1;

    //1.消息体使用回收的资源还是重新malloc
    msg1 = q->recycle_msg;//消息循环使用
    if(msg1){
        q->recycle_msg = msg1->next;
        q->recycle_count++;
    }else{
        q->alloc_count++;// 分配的次数
        msg1 = (AVMessage *)av_malloc(sizeof(AVMessage));//重新分配
    }
    *msg1 = *msg;
    msg1->next = NULL;
    if(!q->first_msg){
        q->first_msg = msg1;
    }else{
        q->last_msg->next = msg1;
    }
    q->last_msg = msg1;
    q->nb_messages++;
    SDL_CondSignal(q->cond);// 条件变量,它用于告知一个或多个正在等待此条件变量的线程:某些条件已经满足,它们可以继续执行了。
    return  0;

}



int msg_queue_put(MessageQueue *q, AVMessage *msg)
{
    int ret;
    SDL_LockMutex(q->mutex);
    ret = msg_queue_put_private(q,msg);
    SDL_UnlockMutex(q->mutex);
    return ret;
}

//插⼊消息
void msg_init_msg(AVMessage *msg)
{
    memset(msg,0,sizeof(AVMessage));//将一段内存空间的内容设置为指定的值。
}

// 插⼊简单消息,只带消息类型,不带参数
void msg_queue_put_simple1(MessageQueue *q, int what)
{
    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = what;
    msg_queue_put(q,&msg);
}
// 插⼊简单消息,只带消息类型,带1个参数
void msg_queue_put_simple2(MessageQueue *q, int what, int arg1)
{
    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = what;
    msg.arg1 = arg1;
    msg_queue_put(q,&msg);
}
// 插⼊简单消息,只带消息类型,带2个参数
void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2)
{
    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = what;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    msg_queue_put(q,&msg);
}
// 释放msg的obj资源
void msg_obj_free_l(void *obj)
{
    av_free(obj);
}
//插⼊消息,带消息类型,带2个参数,带obj
void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len)
{
    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = what;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    msg.obj = av_malloc(obj_len);
    memcpy(msg.obj,obj,obj_len);
    msg.free_l = msg_obj_free_l;
    msg_queue_put(q,&msg);
}
// 消息队列初始化
void msg_queue_init(MessageQueue *q)
{
    memset(q,0,sizeof(MessageQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
    q->abort_request = 1;
}
// 消息队列flush,清空所有的消息
void msg_queue_flush(MessageQueue *q)
{
    AVMessage  *msg, *msg1;
    SDL_LockMutex(q->mutex);
    for(msg = q->first_msg;msg !=NULL;msg = msg1){
        msg1 = msg->next;
        msg->next = q->recycle_msg;
        q->recycle_msg = msg;
    }
    q->last_msg = NULL;
    q->first_msg = NULL;
    q->nb_messages = 0;
    SDL_UnlockMutex(q->mutex);
}
// 消息销毁
void msg_queue_destroy(MessageQueue *q)
{
    msg_queue_flush(q);
    SDL_LockMutex(q->mutex);
    while(q->recycle_msg){
        AVMessage *msg = q->recycle_msg;
        msg_free_res(msg);
        av_freep(&msg);
    }
    SDL_UnlockMutex(q->mutex);
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}
// 消息队列终⽌
void msg_queue_abort(MessageQueue *q)
{
    SDL_LockMutex(q->mutex);
    q->abort_request = 1;
    SDL_CondSignal(q->cond);
    SDL_UnlockMutex(q->mutex);
}
// 启⽤消息队列
void msg_queue_start(MessageQueue *q)
{
    SDL_LockMutex(q->mutex);
    q->abort_request = 0;
    //插入一个消息

    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = FFP_MSG_FLUSH;
    msg_queue_put_private(q,&msg);
    SDL_UnlockMutex(q->mutex);

}
// 读取消息
/* return < 0 if aborted, 0 if no msg and > 0 if msg. */
//从头部first_msg取消息
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
    AVMessage *msg1;
    int ret;
    SDL_LockMutex(q->mutex);// 互斥量
    for(;;){
     if(q->abort_request){
         ret = -1;
         break;
     }
     //获取消息
     msg1 = q->first_msg;
     if(msg1){
         q->first_msg = msg->next;
         if(!q->first_msg)
             q->last_msg = NULL;
         q->nb_messages--;
         *msg = *msg1;
         msg->obj = NULL;
         msg1->next = q->recycle_msg;
         q->recycle_msg = msg1;
         ret = 1;
     }else if(!block){
         ret = 0;
         break;
     }else{
         SDL_CondWait(q->cond,q->mutex);//等待信号量
     }
    }
    return ret;
}

// 消息删除 把队列⾥同⼀消息类型的消息全删除掉
void msg_queue_remove(MessageQueue *q, int what)
{
    AVMessage **p_msg, *msg, *last_msg;
        SDL_LockMutex(q->mutex);

        last_msg = q->first_msg;
        if(!q->abort_request && q->first_msg){
            p_msg = &q->first_msg;
                while(*p_msg){
                    msg = *p_msg;

                    if(msg->what == what){//同类型全部删除
                        *p_msg = msg->next;

                        msg_free_res(msg);
                        msg->next = q->recycle_msg;//消息体回收
                        q->recycle_msg = msg;
                        q->nb_messages--;
                    }else{
                        last_msg = msg;
                        p_msg = &msg->next;
                    }
                }
                if(q->first_msg){
                    q->last_msg = last_msg;
                }else {
                    q->last_msg = NULL;
                }
            }
            SDL_UnlockMutex(q->mutex);
    }
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值