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

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

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

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

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

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

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

超级播放器UML整体架构

#pragma once
#include <mutex>
struct AVFormatContext;
struct AVPacket;
struct AVCodecParameters;
class XDemux
{
public://打开媒体文件,或者流媒体 rtmp http rstpvirtual bool Open(const char *url);//空间需要调用者释放 ,释放AVPacket对象空间,和数据空间 av_packet_freevirtual AVPacket *Read();virtual bool IsAudio(AVPacket *pkt);//获取视频参数  返回的空间需要清理  avcodec_parameters_freevirtual AVCodecParameters *CopyVPara();//获取音频参数  返回的空间需要清理 avcodec_parameters_freevirtual AVCodecParameters *CopyAPara();//seek 位置 pos 0.0 ~1.0virtual 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_sizemux.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()
{
}

本项目下载链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux c 数据写入硬盘分区,Linux操作篇之分区/磁盘扩容(一)

在实际工作中&#xff0c;系统的运行会产生大量的日志 、临时、以及生产文件等数据。所以对磁盘空间也是有一定要求的。但在前期工作中&#xff0c;可能不会需要太大的空间&#xff0c;但是随着后期的使用&#xff0c;存储空间需求很大。这个时候进行扩容就可以了。一般情况下&…

js mztreeview 双击事件_Mac下的Node.js安装教程

前言更多详情&#xff0c;请访问我的 个人博客。什么是Node.jsNodeJS官网上的介绍&#xff1a;Node.js is a platform built on Chromes JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model …

visual2019没有勾选的在如何加入_发票管理系统完成升级,勾选认证平台改头换面,你所有的问题都在这里!...

发票系统2.0版上线为了进一步优化增值税发票系统&#xff0c;提高用户体验&#xff0c;根据国家税务总局安排部署&#xff0c;我省将于2019年11月1日对增值税发票管理系统进行全面升级改造为增值税发票管理系统2.0版。增值税发票综合服务平台是现有增值税发票选择确认平台的升级…

linux 多线程实现倒计时,Linux用脚本实现“时分秒“倒计时功能

1.怎样实现“时分秒“倒计时在Linux下&#xff0c;脚本的完成相对于C语言来说稍微随意一点&#xff0c;可以按照字的想法写&#xff0c;只要有逻辑就可以了。示例&#xff1a;注意&#xff1a;clean的功能这个命令将会刷新屏幕&#xff0c;本质上只是让终端显示页向后翻了一页&…

百分比单位始终根据父元素相应值来计算_CSS Viewport 单位,很多人还不知道使用它来快速布局!...

**CSS Viewport units(视口单位)**在过去几年已经出现了&#xff0c;随着时间的推移&#xff0c;越来越多的开发人员开始使用它们。它们的好处在于为我们提供了一种不需要使用J avaScript 就能以动态的方式调整大小的方法。而且&#xff0c;如果它失效&#xff0c;也有很多备用…

linux macos 界面对比,GNOME 3与Mac OS X 10.7 (Lion)的纵览模式比较

在Twitter上与ibuick同学聊了一些Mac OS X新的设计&#xff0c;还有GNOME等。我突然意识到&#xff0c;Apple并不是引领一切的&#xff0c;很多方面&#xff0c;它甚至是向Linux下的GNOME、KDE学来的(比如出现于Leopard的Space)。更有意思的是&#xff0c;前些日子我刚玩过最新…

【音视频安卓开发 (四)】AndroidStudio项目配置权限、jni库路径、ABI

读写权限 权限(版本) 添加jni用到库所在的路径 设置cmake和NDK参数 cmake项目配置

犀牛重建曲面_【教程】Rhino犀牛面包机建模教学(含模型领取)

建模渲染教学视频可关注◾B站&#xff1a;卓尔谟工业设计小站&#xff1b;◾视频号&#xff1a;学犀牛网校教程&#xff1a;戎尚老师 / 编辑&#xff1a;老白建模步骤01、导入背景&#xff0c;画出面包机半边弧线并镜像&#xff1b;02、对照侧视图高度&#xff0c;用线拉成体&a…

selenium架构_Selenium测试的干净架构

selenium架构在此博客文章中&#xff0c;我想介绍一种具有最佳设计模式的Selenium测试的简洁架构&#xff1a;页面对象&#xff0c;页面元素&#xff08;通常称为HTML包装器&#xff09;以及自行开发的非常小巧的框架。 该体系结构不限于示例中使用的Java&#xff0c;也可以以任…

C++ 【随想录】(四)【Makefile】

编译流程 预处理 gcc -E test.c -o test.i test.c源码进行预处理&#xff0c;预处理后停止编译,预处理后文件体积会变大&#xff0c;且为文本格式 编译 gcc -S test.i -o test.s 编译预处理的文件 汇编 gcc -c test.s -o test.o .s转成二进制文件 链接 gcc te…

mfc从文件中读取数据_Python 中的 bytes、str 以及 unicode 区别

从Python发展历史谈起Python3和Python2表示字符序列的方式有所不同。Python3字符序列的两种表示为byte和str。前者的实例包含原始的8位值&#xff0c;即原始的字节&#xff1b;后者的实例包括Unicode字符。Python2字符序列的两种表示为str和unicode。与Python3不同的是&#xf…

linux字符雨,linux周记

shell脚本基础格式要求&#xff1a;首行shebaang机制#!/bin/bash#!/usr/bin/python#!/usr/bin/perlshell脚本用途&#xff1a;自动化常用命令执行系统管理和故障排除创建简单的应用程序处理文本或文件bash中变量的种类局部变量&#xff1a;生效范围为当前shell进程&#xff1b;…

【音视频安卓开发 (一)】AndroidStudio项目配置权限、jni库路径、ABI、Cmake

cmake项目配置 # For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_require…

string index out of range_Java 12 骚操作, String居然还能这样玩!

坐稳了&#xff0c;准备起飞&#xff01;1、transformtransform&#xff1a;即字符串转换&#xff0c;来看下 transform 的实现源码&#xff1a;public <R> R transform(Function<? super String, ? extends R> f) {return f.apply(this); }传入一个函数式接口 F…

弹性架构_实践中的弹性基础架构

弹性架构几周前&#xff0c;我获得了一个难得的机会&#xff0c;可以在基础设施领域中沾沾自喜。 在JVM内部的深入了解下&#xff0c;我每天的工作经历发生了有趣的变化&#xff0c;我想与您分享动机和成果。 希望它可以启发类似的问题类别。 背景 我将从解释需要解决方案的上…

linux的ctrl alt f6的作用,Linux(Centous6.4)操作系统中,快捷键Alt+Ctrl+F10是什么作用?...

满意答案John_05152017.07.16一些常用快捷键切换到第一个文本终端。在Linux 下你可以有多达六个不同的终端。这个命令的意思是&#xff1a;“同时按住键和键&#xff0c;然后按键&#xff0c;再释放所有的键”。(n1..6)&#xff1a;切换到第n个文本终端。(你也可以使用不是很经…

【TCP丢包重传】

TCP丢包重传机制如果在网络状况最糟糕的情况下就会造成极大的延迟。或者超过2min断开连接。如果这种场景下可以采用UDP。UDP需要解决包的重新排序&#xff0c;丢包等问题。

前端H5怎么切换语言_「自学系列一」HTML5大前端学习路线+视频教程完整版

全新Java、HTML5前端、大数据、Python爬虫、全链UI设计、软件测试、Unity 3D、Go语言等多个技术方向的全套视频。面对这么多的知识点&#xff0c;有的盆友就麻爪了……我是谁&#xff1f;我该从哪里开始看&#xff1f;我该怎么看&#xff1f;我该看多少&#xff1f;这&#xff…

r语言在linux下取数据,菜鸟第一步,跪在数据处:R语言读取数据

1. 温故知坑实践是学习知识的最好途径。之前我讲的内容都非常非常基础&#xff0c;包括&#xff1a;(1)什么是R语言&#xff1f;R语言和Rstudio软件的安装&#xff0c;Rstudio的界面介绍&#xff1b;(2)R语言的基本逻辑&#xff0c;基本数据类型&#xff1b;(3)ggplot基础绘图&…

c语言 桌面程序_C语言编程工具:Dev - C++ 简单安装和使用!新手福利!

工欲善其事&#xff0c;必先利其器。——《论语》# 写在前面有关编译器和开发工具可以查看历史文章。# 下载Dev-C操作系统建议Windows 7或10&#xff0c;直接搜索Dev-C下载&#xff0c;或者sourceforge官网下载链接&#xff1a;https://sourceforge.net/projects/orwelldevcpp/…