ffmpeg播放器实战(播放信息类)

简介: 播放信息类

1.导入我们所需要的头文件

extern"C" {
//SDL#include <SDL.h>//FFMPEG#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavutil/time.h>#include <libswresample/swresample.h>};

2.设置音频最大缓冲区

#define AUDIO_BUFF_MAX_SIZE (uint64_t)(1024 * 10)

3.相关状态

//播放状态enum_PLAY_STATE {
//初始化PLAY_INIT=-1,
//打开PLAY_OPEN=0,
//播放PLAY_PLAY=1,
//暂停PLAY_PAUSE=2,
//停止PLAY_STOP=3,
};
//播放速度enum_PLAY_SPEED {
//0.5倍速PLAY_SLOW=0,
//正常速度PLAY_NORMAL=1,
//二倍速度PLAY_FAST2=2,
//四倍数度PLAY_FAST4=4,
};
//前进后退状态enum_SEEK_FORWARD {
//后退SEEK_BACKWARD=-1,
SEEK_NORMAL=0,
//前进SEEK_FORWARD=1,
};
//解码视频数据structDecodeVideoData {
int64_tptsTime; //单位:msAVFrame*frame;
};
//解码音频速度structDecodeAudioData {
int64_tptsTime; //单位:msintbuffSize;
Uint8*buff;
};

4.头文件主代码

classDataInfo : publicQObject{
Q_OBJECTpublic:
explicitDataInfo(WIdid,QObject*parent=nullptr);
~DataInfo();
SDL_Window*getSDLWind();
voidupdateInfo(AVFormatContext*fCtx,
AVCodecContext*vCtx,
AVCodecContext*aCtx,
SwrContext*sCtx,
AVSampleFormatsFmt,
intvIndex,
intaIndex);
AVFormatContext*getFormatCtx();
AVCodecContext*getVideoCtx();
AVCodecContext*getAudioCtx();
SwrContext*getSwrCtx();
AVSampleFormatgetSampleFmt();
intgetSDLFmt();
intgetVideoIndex();
intgetAudioIndex();
int64_tgetLength();
voidsetPlayTime(int64_tptsTime);
int64_tgetPlayTime();
voidsetDecodeState(boolisStart);
boolgetDecodeState();
voidsetPlayState(intstate);
intgetPlayState();
voidsetPlaySpeed(intspeed);
intgetPlaySpeed();
voidsetPlayVolume(intvolume);
intgetPlayVolume();
voidsetSeekTime(int64_tptsTime);
int64_tgetSeekTime();
voidsetSeekForward(intforward);
intgetSeekForward();
voidsetSeekFlag(boolflag);
boolgetSeekFlag();
voidsetDecodeCache(intsize);
voidvideoPush(AVFrame*frame, int64_tptsTime);
DecodeVideoDatavideoPop();
boolvideoIsEmpty();
boolvideoIsFull();
voidaudioPush(intbuffSize, Uint8*buff, int64_tptsTime);
DecodeAudioDataaudioPop();
DecodeAudioDataaudioFirst();
boolaudioIsEmpty();
boolaudioIsFull();
voiddataListRelease();
voidsetAudioClock(int64_ttime);
int64_tgetAudioClock();
private:
//结构体,描述了一个窗体对象,表示的是会呈现在设备上一个窗体,所有图像的载体SDL_Window*mSDLWind=nullptr;
//AVFormatContext是存储音视频封装格式中包含的信息的结构体,也是FFmpeg中统领全局的结构体,//对文件的封装、编码操作从这里开始。AVFormatContext*mFormatCtx=nullptr;
//AVCodecContext是FFmpeg编解码上下文的结构体,而AVCodec是编解码参数的结构体。//AVCodecContex内部有包含AVCodec、AVCodecInternal、AVRational等结构体,//包含AVCodecID、AVMediaType、AVPixelFormat、AVSampleFormat等枚举类型,//包含视频的width、height、framerate、bitrate等关键参数,//包含音频的samplerate、channels等参数。AVCodecContext*mVideoCtx=nullptr;
AVCodecContext*mAudioCtx=nullptr;
//重采样SwrContext*mSwrCtx=nullptr;
/*AVSampleFormat是FFmpeg多媒体处理库中定义的一个枚举类型,用于表示音频样本的数据格式。它定义了不同的样本格式,包括整型和浮点型等。这些格式可以描述音频样本的位深度、通道数以及存储方式。在FFmpeg中,AVSampleFormat枚举类型定义了以下常见的音频样本格式:AV_SAMPLE_FMT_NONE:无效的样本格式AV_SAMPLE_FMT_U8:无符号8位整型AV_SAMPLE_FMT_S16:有符号16位整型AV_SAMPLE_FMT_S32:有符号32位整型AV_SAMPLE_FMT_FLT:32位浮点型AV_SAMPLE_FMT_DBL:64位浮点型AV_SAMPLE_FMT_U8P:无符号8位整型(平面布局)AV_SAMPLE_FMT_S16P:有符号16位整型(平面布局)AV_SAMPLE_FMT_S32P:有符号32位整型(平面布局)AV_SAMPLE_FMT_FLTP:32位浮点型(平面布局)AV_SAMPLE_FMT_DBLP:64位浮点型(平面布局)*/AVSampleFormatmSampleFormat=AV_SAMPLE_FMT_NONE;
intmSDLFormat=0;
intmVideoIndex=-1;
intmAudioIndex=-1;
boolmDecodeState=false; //解码状态QMutexmPlayMutex;
int64_tmPlayTime=0; //播放位置intmPlayState=PLAY_INIT;         //播放状态intmPlaySpeed=PLAY_NORMAL;       //播放速度intmPlayVolume=SDL_MIX_MAXVOLUME; //播放音量:0-128QMutexmSeekMutex;
int64_tmSeekTime=-1;          //跳转播放intmSeekForward=SEEK_NORMAL; //快进快退boolmSeekFlag=false;
QMutexmVideoListMutex;
QMutexmAudioListMutex;
intmDateListSize=30;
QList<DecodeVideoData>mVideoList;
QList<DecodeAudioData>mAudioList;
QMutexmAudioClockMutex;
int64_tmAudioClock=0;
signals:
};

5.构造函数代码

DataInfo::DataInfo(WIdid,QObject*parent)
    : QObject{parent}
{
//初始化SDL库SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO);
//从原生窗口创建SDL窗口mSDLWind=SDL_CreateWindowFrom((void*)id);
//如果创建成功则显示窗口if (mSDLWind) {
SDL_ShowWindow(mSDLWind);
    }
}

6.资源操作

DataInfo::~DataInfo(){
//销毁SDL窗口SDL_DestroyWindow(mSDLWind);
//清空所有SDL占用资源,并退出SDL_Quit();
}
//获得窗口SDL_Window*DataInfo::getSDLWind()
{
returnmSDLWind;
}

7.更新参数

voidDataInfo::updateInfo(AVFormatContext*fCtx,
AVCodecContext*vCtx,
AVCodecContext*aCtx,
SwrContext*sCtx,
AVSampleFormatsFmt,
intvIndex,
intaIndex)
{
mFormatCtx=fCtx;
mVideoCtx=vCtx;
mAudioCtx=aCtx;
mSwrCtx=sCtx;
mSampleFormat=sFmt;
switch (mSampleFormat) {
caseAV_SAMPLE_FMT_U8:
mSDLFormat=AUDIO_U8;
break;
caseAV_SAMPLE_FMT_S16:
mSDLFormat=AUDIO_S16SYS;
break;
caseAV_SAMPLE_FMT_S32:
mSDLFormat=AUDIO_S32SYS;
break;
caseAV_SAMPLE_FMT_FLT:
mSDLFormat=AUDIO_F32SYS;
break;
default:
mSDLFormat=AUDIO_U8;
break;
    }
mVideoIndex=vIndex;
mAudioIndex=aIndex;
}

8.设置返回设置值

AVFormatContext*DataInfo::getFormatCtx()
{
returnmFormatCtx;
}
AVCodecContext*DataInfo::getVideoCtx()
{
returnmVideoCtx;
}
AVCodecContext*DataInfo::getAudioCtx()
{
returnmAudioCtx;
}
SwrContext*DataInfo::getSwrCtx()
{
returnmSwrCtx;
}
AVSampleFormatDataInfo::getSampleFmt()
{
returnmSampleFormat;
}
intDataInfo::getSDLFmt()
{
returnmSDLFormat;
}
intDataInfo::getVideoIndex()
{
returnmVideoIndex;
}
intDataInfo::getAudioIndex()
{
returnmAudioIndex;
}
int64_tDataInfo::getLength()
{
//获得时间基AVRationaltimeBase=mFormatCtx->streams[mVideoIndex]->time_base;
//计算视频总长度,毫秒为单位returnmFormatCtx->streams[mVideoIndex]->duration*1000*av_q2d(timeBase);
}
voidDataInfo::setPlayTime(int64_tptsTime)
{
mPlayMutex.lock();
mPlayTime=ptsTime;
mPlayMutex.unlock();
}
int64_tDataInfo::getPlayTime()
{
mPlayMutex.lock();
int64_ttime=mPlayTime;
mPlayMutex.unlock();
returntime;
}
voidDataInfo::setDecodeState(boolisStart)
{
mDecodeState=isStart;
}
boolDataInfo::getDecodeState()
{
returnmDecodeState;
}
voidDataInfo::setPlayState(intstate)
{
mPlayState=state;
}
intDataInfo::getPlayState(){
returnmPlayState;
}
voidDataInfo::setPlaySpeed(intspeed)
{
if (speed==PLAY_SLOW||speed==PLAY_NORMAL||speed==PLAY_FAST2||speed==PLAY_FAST4)
mPlaySpeed=speed;
}
intDataInfo::getPlaySpeed()
{
returnmPlaySpeed;
}
voidDataInfo::setPlayVolume(intvolume)
{
if (volume>=0&&volume<=SDL_MIX_MAXVOLUME)
mPlayVolume=volume;
}
intDataInfo::getPlayVolume()
{
returnmPlayVolume;
}
voidDataInfo::setSeekTime(int64_tptsTime)
{
mSeekTime=ptsTime;
}
int64_tDataInfo::getSeekTime()
{
returnmSeekTime;
}
voidDataInfo::setSeekForward(intforward)
{
mSeekMutex.lock();
mSeekForward=forward;
mSeekMutex.unlock();
}
intDataInfo::getSeekForward()
{
mSeekMutex.lock();
intflag=mSeekForward;
mSeekMutex.unlock();
returnflag;
}
voidDataInfo::setSeekFlag(boolflag)
{
mSeekMutex.lock();
mSeekFlag=flag;
mSeekMutex.unlock();
}
boolDataInfo::getSeekFlag()
{
mSeekMutex.lock();
boolflag=mSeekFlag;
mSeekMutex.unlock();
returnflag;
}
voidDataInfo::setDecodeCache(intsize)
{
if (size>=10&&size<=100)
mDateListSize=size;
}
voidDataInfo::videoPush(AVFrame*frame, int64_tptsTime)
{
mVideoListMutex.lock();
DecodeVideoDatadata;
data.ptsTime=ptsTime;
//Fmpeg库中用于克隆AVFrame对象的函数。AVFrame是FFmpeg中表示视频或音频帧的结构体,av_frame_clone函数可以创建一个新的AVFrame,并将源AVFrame的数据复制到新的AVFrame中data.frame=av_frame_clone(frame);
mVideoList.append(data);
mVideoListMutex.unlock();
}
DecodeVideoDataDataInfo::videoPop()
{
mVideoListMutex.lock();
DecodeVideoDatadata;
data.ptsTime=-1;
if (!mVideoList.isEmpty())
data=mVideoList.takeFirst();
mVideoListMutex.unlock();
returndata;
}
boolDataInfo::videoIsEmpty()
{
mVideoListMutex.lock();
boolflag=mVideoList.isEmpty();
mVideoListMutex.unlock();
returnflag;
}
boolDataInfo::videoIsFull()
{
mVideoListMutex.lock();
boolflag= (mVideoList.size() >=mDateListSize);
mVideoListMutex.unlock();
returnflag;
}
voidDataInfo::audioPush(intbuffSize, Uint8*buff, int64_tptsTime)
{
mAudioListMutex.lock();
DecodeAudioDatadata;
data.ptsTime=ptsTime;
data.buffSize=buffSize;
data.buff=buff;
mAudioList.append(data);
mAudioListMutex.unlock();
}
DecodeAudioDataDataInfo::audioPop()
{
mAudioListMutex.lock();
DecodeAudioDatadata;
data.ptsTime=-1;
if (!mAudioList.isEmpty())
//删除首个元素并获取data=mAudioList.takeFirst();
mAudioListMutex.unlock();
returndata;
}
DecodeAudioDataDataInfo::audioFirst()
{
mAudioListMutex.lock();
DecodeAudioDatadata;
data.ptsTime=-1;
if (!mAudioList.isEmpty())
//获取首个元素data=mAudioList.first();
mAudioListMutex.unlock();
returndata;
}
boolDataInfo::audioIsEmpty()
{
mAudioListMutex.lock();
boolflag=mAudioList.isEmpty();
mAudioListMutex.unlock();
returnflag;
}
boolDataInfo::audioIsFull()
{
mAudioListMutex.lock();
boolflag= (mAudioList.size() >=mDateListSize*2);
mAudioListMutex.unlock();
returnflag;
}
voidDataInfo::dataListRelease()
{
mVideoListMutex.lock();
for (auto&data : mVideoList) {
av_frame_free(&data.frame);
data.frame=nullptr;
    }
mVideoList.clear();
mVideoListMutex.unlock();
mAudioListMutex.lock();
for (auto&data : mAudioList) {
//av_free 是FFmpeg库中的一个函数,用于释放AVCodecContext、AVFormatContext//和其他相关结构体的内存。它可以在不需要这些结构体时,主动释放它们所占用的内存,//以便节省资源并避免内存泄漏。使用 av_free 函数时,需要确保传入的指针有效,//并且已经完成了相应的初始化和使用av_free(data.buff);
data.buff=nullptr;
    }
mAudioList.clear();
mAudioListMutex.unlock();
}
voidDataInfo::setAudioClock(int64_ttime)
{
mAudioClockMutex.lock();
mAudioClock=time;
mAudioClockMutex.unlock();
}
int64_tDataInfo::getAudioClock()
{
mAudioClockMutex.lock();
int64_ttime=mAudioClock;
mAudioClockMutex.unlock();
returntime;
}


相关文章
|
6月前
|
XML 编解码 JSON
FFmpeg常用命令讲解及实战二(2)
FFmpeg常用命令讲解及实战二
83 0
|
25天前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
100 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
1月前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
126 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
|
1月前
|
缓存 监控 计算机视觉
视频监控笔记(三):opencv结合ffmpeg获取rtsp摄像头相关信息
本文介绍了如何使用OpenCV结合FFmpeg获取RTSP摄像头信息,包括网络架构、视频监控系统组成、以及如何读取和显示网络摄像头视频流。
41 1
|
3月前
|
机器学习/深度学习 编解码 API
【机器学习】FFmpeg+Whisper:二阶段法视频理解(video-to-text)大模型实战
【机器学习】FFmpeg+Whisper:二阶段法视频理解(video-to-text)大模型实战
52 0
|
5月前
|
存储 编解码 Linux
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
62 1
|
6月前
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
《FFmpeg开发实战》一书中,第10章示例程序playaudio.c原本仅支持mp3和aac音频播放。为支持ogg、amr、wma等非固定帧率音频,需进行三处修改:1)当frame_size为0时,将输出采样数量设为512;2)遍历音频帧时,计算实际采样位数以确定播放数据大小;3)在SDL音频回调函数中,确保每次发送len字节数据。改进后的代码在chapter10/playaudio2.c,可编译运行播放ring.ogg测试,成功则显示日志并播放铃声。
115 1
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
|
6月前
|
编解码 API 开发工具
FFmpeg获取音视频流信息
FFmpeg获取音视频流信息
135 1
FFmpeg获取音视频流信息
|
6月前
|
Web App开发 编解码 vr&ar
使用FFmpeg从音视频处理到流媒体技术的探索和实战应用
使用FFmpeg从音视频处理到流媒体技术的探索和实战应用
286 2
|
6月前
|
编解码 计算机视觉 索引
使用ffmpeg MP4转 m3u8并播放 实测!!
使用ffmpeg MP4转 m3u8并播放 实测!!
313 1