BPlay1.0系列(4:Bffmpeg单例模式设计+媒体流文件检测)

上一节成功装载了ffmpeg库,接下来就是媒体文件的载入检测,但是在实际实现时发现:
Bffmpeg加载媒体文件时,需要记录媒体文件相关信息:上下文、音视频索引等,这些需要定义成员变量保存在Bffmpeg类中,加载文件的方法如果定义成静态成员函数,那么将无法访问到保存的媒体信息变量,如果定义成普通成员函数,则需要实例化一个对象,但该对象在工程中只需要一个即可。基于以上考虑,最后选择采用单例模式来设计Bffmpeg。

1、为Bffmpeg添加单例模式

首先想要添加静态成员方法GetInstance用于获取实例对象,构造函数想要私有化,防止在其他地方被实例化,还需要添加单例实例对象和Bffmpeg对象锁:

class Bffmpeg : QThread
{
public:
    static Bffmpeg* GetInstance();              /* 获取单例实例对象 */
private:
    Bffmpeg();
    static QAtomicPointer<Bffmpeg> Instance;    /* 单例实例对象 */
    static QMutex ffmpegMutex;                  /* Bffmpeg对象锁 */
};

GetInstance的实现如下:

/********************************
 * Bffmpeg* Bffmpeg::GetInstance()
 * 功能:获取单例实例对象
 *      返回:单例实例对象
 * *****************************/
Bffmpeg* Bffmpeg::GetInstance()
{
    /*
     testAndSetOrdered实现逻辑:
        testAndSetOrdered(expectedValue, newValue)
        currentValue = _instance;   //currentValue为QAtomicPointer<Bffmpeg>模板定义的指针变量
        if (currentValue == expectedValue) {
            currentValue = newValue;
            return true;
        }
        return false;
    */
    if (Instance.testAndSetOrdered(NULL, NULL)) {
        QMutexLocker lock(&ffmpegMutex);
        Instance.testAndSetOrdered(NULL, new Bffmpeg);
    }

    return Instance;
}

2、媒体流文件检测

打开文件按钮点击回调函数需要改成单例模式来设计,代码修改后:

/********************************
 * void MainWindow::on_Bopenfile_btn_clicked()
 * 功能:打开文件按钮点击回调函数
 * *****************************/
void MainWindow::on_Bopenfile_btn_clicked()
{
    QString FilePath = QFileDialog::getOpenFileName(this, QString("媒体文件"), QString("."), QString("视频文件(*.mp4 *.flv *.avi);;所有文件(*.*)"));
    if (FilePath.isEmpty()) {
        BLOG("Media File empty");
        return;
    }

    if (0 != Bffmpeg::GetInstance()->BLoadMediaFile(FilePath)) {
        BLOG("Media File illegal");
        return;
    }

    return;
}

为Bffmpeg添加媒体信息相关变量,媒体流上下文FormatContext,视频流索引Video_index和音频流索引Audio_index:

class Bffmpeg : QThread
{
public:
    static Bffmpeg* GetInstance();              /* 获取单例实例对象 */

    int BLoadMediaFile(QString FilePath);       /* 媒体文件加载 */

private:
    Bffmpeg();
    static QAtomicPointer<Bffmpeg> Instance;    /* 单例实例对象 */
    static QMutex ffmpegMutex;                  /* Bffmpeg对象锁 */
    AVFormatContext *FormatContext = NULL;      /* 媒体流上下文 */
    int Video_index;                            /* 视频流索引 */
    int Audio_index;                            /* 音频流索引 */
};

继续扩充BLoadMediaFile方法:

/********************************
 * int Bffmpeg::BLoadMediaFile(QString FilePath)
 * 功能:媒体文件加载
 *      成功返回:0
 *      失败返回:errcode
 * *****************************/
int Bffmpeg::BLoadMediaFile(QString FilePath)
{
    int Ret = 0;
    char errbuf[128] = {0};

    if (NULL != FormatContext) {
        avformat_close_input(&FormatContext);
    }

    FormatContext = avformat_alloc_context();

    /* 打开多媒体数据并且获得一些相关的信息 */
    Ret = avformat_open_input(&FormatContext, FilePath.toLocal8Bit().data(), NULL, NULL);
    if (Ret != 0) {
        av_strerror(Ret, errbuf, sizeof(errbuf));
        BLOG("avformat_open_input fail, Ret[%d], Err[%s]", Ret, errbuf);
        return Ret;
    }

    /* 读取一部分音视频数据并且获得一些相关的信息 */
    Ret = avformat_find_stream_info(FormatContext, NULL);
    if (Ret < 0) {
        av_strerror(Ret, errbuf, sizeof(errbuf));
        BLOG("avformat_open_input fail, Ret[%d], Err[%s]", Ret, errbuf);
        avformat_close_input(&FormatContext);
        return Ret;
    }

    /* 查找视频流索引 */
    Video_index  = av_find_best_stream(FormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if ((AVERROR_STREAM_NOT_FOUND == Video_index) || (AVERROR_DECODER_NOT_FOUND== Video_index)) {
        BLOG("av_find_best_stream fail, Video_index[%d]", Video_index);
        avformat_close_input(&FormatContext);
        return -1;
    }

    /* 找视频解码器 */
    AVCodec *Codec = avcodec_find_decoder(FormatContext->streams[Video_index]->codecpar->codec_id);
    if (NULL == Codec) {
        BLOG("avcodec_find_decoder fail");
        avformat_close_input(&FormatContext);
        return -1;
    }

    /* 打开解码器,初始化FormatContext内部解码器上下文,FormatContext->streams[Video_index]->codec内存在avformat_open_input调用时已分配 */
    Ret = avcodec_open2(FormatContext->streams[Video_index]->codec, Codec, NULL);
    if (Ret < 0) {
        av_strerror(Ret, errbuf, sizeof(errbuf));
        BLOG("avcodec_open2 fail, Ret[%d], Err[%s]", Ret, errbuf);
        avformat_close_input(&FormatContext);
        return Ret;
    }
    
    /* 查找音频流索引 */
    Audio_index  = av_find_best_stream(FormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if ((AVERROR_STREAM_NOT_FOUND == Audio_index) || (AVERROR_DECODER_NOT_FOUND== Audio_index)) {
        BLOG("av_find_best_stream fail, Audio_index[%d]", Audio_index);
        avformat_close_input(&FormatContext);
        return -1;
    }

    /* 找音频解码器 */
    Codec = avcodec_find_decoder(FormatContext->streams[Audio_index]->codecpar->codec_id);
    if (NULL == Codec) {
        BLOG("avcodec_find_decoder fail");
        avformat_close_input(&FormatContext);
        return -1;
    }

    /* 打开解码器,初始化FormatContext内部解码器上下文,FormatContext->streams[Audio_index]->codec内存在avformat_open_input调用时已分配 */
    Ret = avcodec_open2(FormatContext->streams[Audio_index]->codec, Codec, NULL);
    if (Ret < 0) {
        av_strerror(Ret, errbuf, sizeof(errbuf));
        BLOG("avcodec_open2 fail, Ret[%d], Err[%s]", Ret, errbuf);
        avformat_close_input(&FormatContext);
        return Ret;
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值