C/C++ 视频播放器开发


前言

如果对学习C/C++有兴趣,可以看看这篇文章哦:C/C++教程

C/C++开发方向之一就是音视频,本文以当前流行的VLC开源库为基础,开发一个视频播放器。

在这里插入图片描述

一、下载VLC库

最新库的下载地址点这里
在这里插入图片描述
可选择自己需要的版本,我下载的为win64
在这里插入图片描述
下载压缩包,解压,将图中两个dll和一个文件夹复制到项目文件中
在这里插入图片描述
进入sdk库
在这里插入图片描述
将这两个文件夹拷贝到自己的项目文件中去
在这里插入图片描述
此时项目文件如下:
在这里插入图片描述
回到项目中,添加includelib文件夹到项目配置中
在这里插入图片描述
添加如下代码即可正常使用
在这里插入图片描述

typedef long long ssize_t; //目前需要定义,否则编译失败
#include<vlc/vlc.h>  //添加头文件 
#pragma comment(lib,"libvlc.lib") //添加libvlc.lib库
#pragma comment(lib,"libvlccore.lib") //添加libvlccore.lib库

二、VLC使用介绍

  • 创建vlc实例:libvlc_new
  • 为要播放的视频创建媒体实例:libvlc_media_new_path
  • 为媒体实例创建一个播放对象:libvlc_media_player_new_from_media
  • 对播放对象进行一系列操作,比如播放、暂停、停止,调整音量等
  • 释放前三步创建的实例:libvlc_media_player_release,libvlc_media_release,libvlc_release

代码演示:

typedef long long ssize_t; //目前需要定义,否则编译失败
#include<vlc/vlc.h>  //添加头文件 
#include<string>
#include<Windows.h>
#pragma comment(lib,"libvlc.lib") //添加libvlc.lib库
#pragma comment(lib,"libvlccore.lib") //添加libvlccore.lib库
std::string toUTF8(std::wstring data) {
    
    
	int len=WideCharToMultiByte(CP_UTF8,0,data.data(),-1,0,0,0,0);
	std::string s;
	s.resize(len+1);
	WideCharToMultiByte(CP_UTF8,0,data.data(),-1,(LPSTR)s.data(),len+1, 0, 0);
	return s;
}
int main() {
    
    
	libvlc_instance_t* vlc_ins = libvlc_new(0,NULL); //创建vlc实例
	std::string path = toUTF8(L"测试视频.mp4"); //转码为UTF-8
	libvlc_media_t* media = libvlc_media_new_path(vlc_ins,path.data());//为视频创建播放对象
	libvlc_media_player_t * player=libvlc_media_player_new_from_media(media); //创建播放对象
	do {
    
    
		int ret=libvlc_media_player_play(player); //进行播放
		if (ret == -1) break;
		Sleep(1000);  //休眠1秒,给时间缓存,否则数据可能获取失败
		libvlc_time_t tm = libvlc_media_player_get_length(player); //获得视频长度
		printf("%02lld:%02lld:%02lld\n", tm / 3600000, tm / 60000 % 60, tm /1000 % 60);
		int width=libvlc_video_get_width(player); //获取视频宽度
		int hight=libvlc_video_get_height(player); //获取视频高度
		printf("width=%d height=%d\n",width,hight);
		getchar(); //等待一次按键
		libvlc_media_player_pause(player); //暂停视频播放
		getchar();
		libvlc_media_player_play(player);//视频继续播放
		getchar();
		libvlc_media_player_stop(player); //停止视频播放
		getchar();
	} while (0);
	libvlc_media_player_release(player); //释放播放实例
	libvlc_media_release(media); //释放媒体实例
	libvlc_release(vlc_ins); //释放VLC实例
}

几点说明:

  • vlc库默认为utf-8编码,如果文件名中有中文,必须先转化为UTF-8编码
  • do{}while(0)结构可能觉得奇怪,这是为了中途出错,直接跳出循环,释放实例
  • 获取的视频长度以微秒作为单位
  • 名字叫测试视频.mp4放在了当前项目目录下,如果在其它目录,需要指定完整路径
    在这里插入图片描述

运行结果:
在这里插入图片描述

视频正常播放

三、成品演示

在这里插入图片描述
基本功能都实现了,可能存在一定的小bug,可自己稍微修复一下

项目下载可点击这里

四、开始开发

功能需求:播放,暂停/继续,停止,速率,进度显示,跳转位置,地址输入等功能

主要模块:封装VLC库函数为一个简单易用的类

界面:采用MFC的对话框项目
在这里插入图片描述

UI设计

选择MFC项目在这里插入图片描述
取名
在这里插入图片描述
选择项目属性:

注意,除了应用程序类型必须选基于对话框,其它可随意
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后点击确定,生成项目

在这里插入图片描述
拖动控件,设计UI,结果如下:
在这里插入图片描述

封装VLC库

CVlc.h

#pragma once
#include<string>
typedef long long ssize_t;
#include<vlc/vlc.h>
struct MediaSize {
    
    
	int width;
	int hight;
	MediaSize(int _width,int _hight) {
    
    
		width = _width;
		hight = _hight;
	}
};
class CVlc
{
    
    
private:
	libvlc_instance_t* m_instance;
	libvlc_media_t* m_media;
	libvlc_media_player_t* m_player;
	HWND m_hWnd;
private:
	//转换编码为utf-8
	std::string ToUTF8(const std::wstring& str);
public:
	CVlc();
	~CVlc();
	//加载媒体
	bool LoadMedia(const std::wstring &path);
	//设置播放窗口
	void SetHWnd(HWND hWnd);
	//播放
	bool Play();
	//暂停
	bool Pause();
	//停止
	bool Stop();
	//获取播放进度
	float GetPosition();
	//设置播放进度
	void SetPosition(float pos);
	//获取音量
	int GetVolume();
	//设置音量
	void SetVolume(int volume);
	//获取媒体时长
	int GetLenth();
	//设置播放速率
	bool SetRate(float rate);
	//获取媒体宽高
	MediaSize GetMediaInfo();
};

CVlc.cpp

#include "pch.h"
#include "CVlc.h"

std::string CVlc::ToUTF8(const std::wstring& str)
{
    
    
	int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, 0, 0, 0, 0);
	std::string s;
	s.resize(len + 1);
	WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, (LPSTR)s.data(), len + 1, 0, 0);
	return s;
}

CVlc::CVlc()
{
    
    
	m_instance = libvlc_new(0, NULL);
	m_media = NULL;
	m_player = NULL;
	m_hWnd = NULL;
}

CVlc::~CVlc()
{
    
    
	if (m_player != NULL) {
    
    
		libvlc_media_player_release(m_player);
		m_player = NULL;
	}
	if (m_media != NULL) {
    
    
		libvlc_media_release(m_media);
		m_media = NULL;
	}
	if (m_instance != NULL) {
    
    
		libvlc_release(m_instance);
		m_instance = NULL;
	}
}

bool CVlc::LoadMedia(const std::wstring& path)
{
    
    
	if (m_instance == NULL) return false;
	std::string s=ToUTF8(path);
	if (m_media != NULL) {
    
    
		libvlc_media_release(m_media);
		m_media = NULL;
	}
	m_media=libvlc_media_new_location(m_instance,s.data());
	if (m_media == NULL) return false;
	if (m_player != NULL) {
    
    
		libvlc_media_player_release(m_player);
		m_player = NULL;
	}
	m_player=libvlc_media_player_new_from_media(m_media);
	if (m_player == NULL) return false;
	return true;
}

void CVlc::SetHWnd(HWND hWnd)
{
    
    
	m_hWnd = hWnd;
}

bool CVlc::Play()
{
    
    
	if (m_player == NULL) return false;
	if (m_hWnd != NULL) {
    
    
		libvlc_media_player_set_hwnd(m_player, m_hWnd);
	}
	int ret = libvlc_media_player_play(m_player);
	return ret == 0;
}

bool CVlc::Pause()
{
    
    
	if (m_player == NULL) return false;
	libvlc_media_player_pause(m_player);
	return true;
}

bool CVlc::Stop()
{
    
    
	if (m_player == NULL) return false;
	libvlc_media_player_stop(m_player);
	return true;
}

float CVlc::GetPosition()
{
    
    
	if (m_player == NULL) return false;
	return libvlc_media_player_get_position(m_player);
}

void CVlc::SetPosition(float pos)
{
    
    
	if (m_player == NULL) return;
	 libvlc_media_player_set_position(m_player,pos);
}

int CVlc::GetVolume()
{
    
    
	if (m_player == NULL) return 0;
	return libvlc_audio_get_volume(m_player);
}

void CVlc::SetVolume(int volume)
{
    
    
	if (m_player == NULL) return;
	libvlc_audio_set_volume(m_player,volume);
}

int CVlc::GetLenth()
{
    
    
	if (m_player == NULL) return -1;
	libvlc_time_t tm=libvlc_media_player_get_length(m_player);
	if (tm == -1) return -1;
	return tm/1000;
}

bool CVlc::SetRate(float rate)
{
    
    
	if (m_player == NULL) return false;
	return 0==libvlc_media_player_set_rate(m_player,rate);
}

MediaSize CVlc::GetMediaInfo()
{
    
    
	if (m_player == NULL) return MediaSize(0,0);
	return MediaSize(
		libvlc_video_get_width(m_player),
		libvlc_video_get_height(m_player)
	);
}

UI与CVLC类结合

全局变量:
在这里插入图片描述

初始化


BOOL CVideoPlayerDlg::OnInitDialog()
{
    
    
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	//初始化控件
	SetDlgItemText(IDC_ST_TIME, _T("--/--"));
	m_volume.SetRange(0, 100);
	m_volume.SetTicFreq(10);
	SetDlgItemText(IDC_ST_VOLUME, _T("100%"));
	
	m_vlc.SetHWnd(m_video.GetSafeHwnd()); //设置播放窗口

	m_rate.SetCurSel(0); //初始化倍率为1
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

播放按钮

void CVideoPlayerDlg::OnBnClickedPlay()
{
    
    
	if (m_isPlay) {
    
     //如果正在播放,则应该暂停
		KillTimer(0); //删除定时器
		SetDlgItemText(IDC_PLAY, _T("播放"));
		m_vlc.Pause(); //播放暂停
		m_isPlay = !m_isPlay;
		return;
	}

	CString url;
	m_url.GetWindowTextW(url);
	bool ret = m_vlc.LoadMedia(url.GetBuffer());	//加载视频
	if (!ret) {
    
    
		AfxMessageBox(L"加载媒体失败");
		return;
	}
	ret = m_vlc.Play();
	if (!ret) {
    
    
		AfxMessageBox(L"播放视频失败");
		return;
	}
	m_len= 0;
	while (m_len == 0) {
    
     //循环直到获取到视频的长度
		Sleep(20);
		m_len = m_vlc.GetLenth();
	}
	if (m_len != -1) {
    
     //获取长度不出错则设置对应控件
		m_pos.SetRange(0, m_len);
		m_pos.SetTicFreq(m_len / 10);
		CString time;
		time.Format(_T("00:00:00/%02d:%02d:%02d"), m_len / 3600, m_len / 60 % 60, m_len % 60);
		SetDlgItemText(IDC_ST_TIME, time);
	}
	SetDlgItemText(IDC_PLAY, _T("暂停"));
	m_isPlay = !m_isPlay;
	SetTimer(0, 500, NULL);
}

暂停按钮

void CVideoPlayerDlg::OnBnClickedStop()
{
    
    
	KillTimer(0);
	SetDlgItemText(IDC_PLAY, _T("播放"));
	m_isPlay = false;
	m_vlc.Stop();
}

进度条响应函数


void CVideoPlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    
    
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (nSBCode == 5) {
    
    
		TRACE("%d\n", nPos);
		CString time;
		time.Format(_T("%02d:%02d:%02d/%02d:%02d:%02d"),nPos/3600,nPos/60%60,nPos%60, m_len / 3600, m_len / 60 % 60, m_len % 60);
		SetDlgItemText(IDC_ST_TIME, time);
		m_vlc.SetPosition(nPos*1.0/m_len);
	}
	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

音量响应函数

void CVideoPlayerDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    
    
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (nSBCode == 5) {
    
    
		CString strVol;
		strVol.Format(_T("%d%%"), 100 - nPos);
		SetDlgItemText(IDC_ST_VOLUME, strVol);
		m_vlc.SetVolume(100 - nPos);
	}
	CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

播放速率响应事件

void CVideoPlayerDlg::OnCbnSelchangeCbRate()
{
    
    
	int i=m_rate.GetCurSel();
	switch (i)
	{
    
    
	case 0:
		m_vlc.SetRate(1);
		break;
	case 1:
		m_vlc.SetRate(1.5);
		break;
	case 2:
		m_vlc.SetRate(2);
		break;
	default:
		break;
	}
}

定时器响应事件

void CVideoPlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
    
    
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (nIDEvent == 0) {
    
    
		//todo:获取播放状态
		float pos=m_vlc.GetPosition();
		m_pos.SetTic(int(pos*m_len));
		CString time;
		time.Format(_T("%02d:%02d:%02d/%02d:%02d:%02d"), int(pos * m_len) / 3600, int(pos * m_len) / 60 % 60, int(pos * m_len) % 60, m_len / 3600, m_len / 60 % 60, m_len % 60);
		SetDlgItemText(IDC_ST_TIME, time);
	}
	CDialogEx::OnTimer(nIDEvent);
}

猜你喜欢

转载自blog.csdn.net/weixin_50964512/article/details/123778750