【开源项目】超级播放器1.0

面向对象开发的五大基本原则 

单一职责 ===== 各个模块相对独立,优点一:在修改其中某个模块的时候不会对其他模块造成影响;优点二:可以对各个模块进行单独的测试;例如解封装模块和解码模块相互独立设计。

开闭原则 ===== 对扩展开发,修改封闭。例如增加一个功能时,对之前的业务逻辑不需要变更,只需要添加新的方案。

替换原则 ===== 一个类的派生类可以直接替换基类的方法。保证基类接口功能不变,子类去实现自己的接口方法。

接口隔离 =====  内部对用户进行隔离,使用户只使用我们提供的公共接口。

依赖倒置 =====  尽量依靠抽象来编程,外部变成全部是基于抽象接口来编程。

超级播放器UML整体架构

#pragma once
#include <mutex>
struct AVFormatContext;
struct AVPacket;
struct AVCodecParameters;
class XDemux
{
public:

	//打开媒体文件,或者流媒体 rtmp http rstp
	virtual bool Open(const char *url);

	//空间需要调用者释放 ,释放AVPacket对象空间,和数据空间 av_packet_free
	virtual AVPacket *Read();

	virtual bool IsAudio(AVPacket *pkt);

	//获取视频参数  返回的空间需要清理  avcodec_parameters_free
	virtual AVCodecParameters *CopyVPara();

	//获取音频参数  返回的空间需要清理 avcodec_parameters_free
	virtual AVCodecParameters *CopyAPara();

	//seek 位置 pos 0.0 ~1.0
	virtual bool Seek(double pos);

	//清空读取缓存
	virtual void Clear();
	virtual void Close();


	XDemux();
	virtual ~XDemux();

	//媒体总时长(毫秒)
	int totalMs = 0;
	int width = 0;
	int height = 0;
	int sampleRate = 0;
	int channels = 0;
protected:
	std::mutex mux;
	//解封装上下文
	AVFormatContext *FormatContext = NULL;
	//音视频索引,读取时区分音视频
	int videoStream = 0;
	int audioStream = 1;

};

#include "XDemux.h"
#include <iostream>
using namespace std;
extern "C" {
#include "libavformat/avformat.h"
}

static double r2d(AVRational r)
{
	return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}

bool XDemux::Open(const char *url)
{
	//防止重复打开先进行关闭
	Close();
	//参数设置
	//AVDictionary *opts = NULL;
	设置rtsp流已tcp协议打开
	//av_dict_set(&opts, "rtsp_transport", "tcp", 0);

	网络延时时间
	//av_dict_set(&opts, "max_delay", "500", 0);
	//加锁防止多线程重复操作
	mux.lock();
	int re = avformat_open_input(
		&FormatContext,
		url,
		NULL,  // 0表示自动选择解封器
		NULL //参数设置,比如rtsp的延时时间
	);
	if (re != 0)
	{
		mux.unlock();
		char buf[1024] = { 0 };
		av_strerror(re, buf, sizeof(buf) - 1);
		cout << "open " << url << " failed! :" << buf << endl;
		return false;
	}
	cout << "open " << url << " success! " << endl;

	//获取流信息 
	re = avformat_find_stream_info(FormatContext, 0);

	//总时长 毫秒
	int totalMs = FormatContext->duration / (AV_TIME_BASE / 1000);
	cout << "totalMs = " << totalMs << endl;

	//打印视频流详细信息
	av_dump_format(FormatContext, 0, url, 0);


	//获取视频流
	videoStream = av_find_best_stream(FormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	AVStream *as = FormatContext->streams[videoStream];
	width = as->codecpar->width;
	height = as->codecpar->height;

	cout << "=======================================================" << endl;
	cout << videoStream << "视频信息" << endl;
	cout << "codec_id = " << as->codecpar->codec_id << endl;
	cout << "format = " << as->codecpar->format << endl;
	cout << "width=" << as->codecpar->width << endl;
	cout << "height=" << as->codecpar->height << endl;
	//帧率 fps 分数转换
	cout << "video fps = " << r2d(as->avg_frame_rate) << endl;

	cout << "=======================================================" << endl;
	cout << audioStream << "音频信息" << endl;
	//获取音频流
	audioStream = av_find_best_stream(FormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	as = FormatContext->streams[audioStream];
	sampleRate = as->codecpar->sample_rate;
	channels = as->codecpar->channels;

	cout << "codec_id = " << as->codecpar->codec_id << endl;
	cout << "format = " << as->codecpar->format << endl;
	cout << "sample_rate = " << as->codecpar->sample_rate << endl;
	//AVSampleFormat;
	cout << "channels = " << as->codecpar->channels << endl;
	//一帧数据?? 单通道样本数 
	cout << "frame_size = " << as->codecpar->frame_size << endl;
	//1024 * 2 * 2 = 4096  fps = sample_rate/frame_size
	mux.unlock();


	return true;
}
//清空读取缓存
void XDemux::Clear()
{
	mux.lock();
	if (!FormatContext)
	{
		mux.unlock();
		return;
	}
	//清理读取缓冲
	avformat_flush(FormatContext);
	mux.unlock();
}
void XDemux::Close()
{
	mux.lock();
	if (!FormatContext)
	{
		mux.unlock();
		return;
	}
	avformat_close_input(&FormatContext);
	//媒体总时长(毫秒)
	totalMs = 0;
	mux.unlock();
}

//seek 位置 pos 0.0 ~1.0
bool XDemux::Seek(double pos)
{
	mux.lock();
	if (!FormatContext)
	{
		mux.unlock();
		return false;
	}
	//清理读取缓冲,防止网络流粘包
	avformat_flush(FormatContext);

	long long seekPos = 0;
	seekPos = FormatContext->streams[videoStream]->duration * pos;
	int re = av_seek_frame(FormatContext, videoStream, seekPos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
	mux.unlock();
	if (re < 0) return false;
	return true;
}
//获取视频参数  返回的空间需要清理  avcodec_parameters_free
AVCodecParameters *XDemux::CopyVPara()
{
	mux.lock();
	if (!FormatContext)
	{
		mux.unlock();
		return NULL;
	}
	AVCodecParameters *pa = avcodec_parameters_alloc();
	avcodec_parameters_copy(pa, FormatContext->streams[videoStream]->codecpar);
	mux.unlock();
	return pa;
}

//获取音频参数  返回的空间需要清理 avcodec_parameters_free
AVCodecParameters *XDemux::CopyAPara()
{
	mux.lock();
	if (!FormatContext)
	{
		mux.unlock();
		return NULL;
	}
	AVCodecParameters *pa = avcodec_parameters_alloc();
	avcodec_parameters_copy(pa, FormatContext->streams[audioStream]->codecpar);
	mux.unlock();
	return pa;
}
bool XDemux::IsAudio(AVPacket *pkt)
{
	if (!pkt) return false;
	if (pkt->stream_index == videoStream)
		return false;
	return true;

}
//空间需要调用者释放 ,释放AVPacket对象空间,和数据空间 av_packet_free
AVPacket *XDemux::Read()
{
	//防止Open被线程性关掉
	mux.lock();
	if (!FormatContext) //容错
	{
		mux.unlock();
		return 0;
	}
	//定义一个临时的AVPacket用于解码使用
	AVPacket *pkt = av_packet_alloc();
	//读取一帧,并分配空间
	int re = av_read_frame(FormatContext, pkt);
	if (re != 0)
	{
		mux.unlock();
		av_packet_free(&pkt);
		return 0;
	}
	//pts转换为毫秒
	pkt->pts = pkt->pts*(1000 * (r2d(FormatContext->streams[pkt->stream_index]->time_base)));
	pkt->dts = pkt->dts*(1000 * (r2d(FormatContext->streams[pkt->stream_index]->time_base)));
	mux.unlock();
	cout << "**********************************\n";
	cout << "PKT DTS:   " << pkt->dts << endl;
	cout << "PKT PTS:   " << pkt->pts << endl;
	/*cout << pkt->pts << " " << flush;*/
	return pkt;

}
XDemux::XDemux()
{
	//防止多线程访问不会出现问题
	static bool isFirst = true;
	//每次只进一个线程,只内部知道 外部不需要知道
	static std::mutex dmux;
	dmux.lock();
	if (isFirst)
	{
		//初始化封装库
		av_register_all();

		//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)
		avformat_network_init();
		isFirst = false;
	}
	dmux.unlock();
}


XDemux::~XDemux()
{
}

本项目使用QT5.9 FFmpeg4.2.1 

本项目下载链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
超级播放器是一款简单好用的万能播放器。软件支持各种主流的媒体文件播放,将文件播放和网络影视无缝结合,还能享受全球400多套超高清晰的卫星电视节目和海量激情视频。更具有去除视频前贴片广告功能。是用户实现视频观看功能的好帮手。 超级播放器(网络影视)功能 一、可以播放现在流行的几乎所有的 1、光盘文件(.dat;.cda;.vob等); 2、视频文件(.avi;.mpg;.mpeg;.wmv;.rm等); 3、音频文件(.wav;.mp3;.mid;.midi等); 4、图像文件(.bmp;.gif;.jpg;.tif;.tiff;.ico;.cur;.dib;.wmf;.emf等); 5、Flash文件(.swf等); 6、其他文件(.zcy;.asf;.asx;.wn;.wmx;.wmp;.wma;.wax;.wvx;.rmi); 7、网络影视节目(内置400多套超高清晰的卫星电视节目和海量激情视频)。 二、可以自动搜索播放指定目录下的所有播放文件。 三、具有视频、音频、图像和Flash文件预览功能,不需要打开文件即可查看。 四、可以将任何图像加入《超级播放器(网络影视)》当作画面背景图(将您的全家福作为开始画面是不是特别温馨啊! 五、可以控制图像随意显示和任意打印。 六、超级播放器(网络影视)同时支持播放文件拖放功能,即:将文件拖进播放器即可播放。 七、具有增强的鼠标控制功能,鼠标左键双击可以控制全屏幕播放或恢复视窗,鼠标右击可弹出快捷菜单,单击鼠标中键可以暂停或重新播放。 八、另外,超级播放器(网络影视)播放文件可以不受文件后缀影响,甚至可以播放游戏中隐藏的视频、音频和图像文件。 九、内置的网络影视功能可以让您放眼全世界。 超级播放器(网络影视)截图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

༄yi笑奈何

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值