小编心语:现下,各种视频播放软件层出不穷,竞争也越演越烈,不知道大家有木有这个想法,小编有时在想能不能做一款属于自己的视频播放器呢~小编特意去实验楼,整理出了这篇关于如何实现简易视频播放器的博文。简易播放器,你值得拥有~

友情提示:这里只是前篇,只是一些简单的功能,其他功能将会在后篇为大家介绍——

C语言基于GTK+Libvlc实现的简易视频播放器

一、课程说明

如果你学习过之前上线的pygtk实现有道词典的项目课,那应该对gtk的使用有一些了解了,这个项目课学起来会相对轻松一些。 关于Gtk或者说是通常的图形应用开发的一些基础知识,我们会在以后的基础课程中体现,项目课适合有一定基础的用户学习。

二、Gtk简介

GTK+ 是一种图形用户界面(GUI)工具包。也就是说,它是一个库(或者,实际上是若干个密切相关的库的集合),它支持创建基于 GUI 的应用程序。可以把 GTK+ 想像成一个工具包,从这个工具包中可以找到用来创建 GUI 的许多已经准备好的构造块。

最初,GTK+ 是作为另一个著名的开放源码项目 —— GNU Image Manipulation Program (GIMP) —— 的副产品而创建的。在开发早期的 GIMP 版本时,Peter Mattis 和 Spencer Kimball 创建了 GTK(它代表 GIMP Toolkit),作为 Motif 工具包的替代,后者在那个时候不是免费的。(当这个工具包获得了面向对象特性和可扩展性之后,才在名称后面加上了一个加号。)

这差不多已经 10 年过去了。今天,在 GTK+ 的最新稳定版本 —— 2.8 版上(3.0测试中),仍然在进行许多活动,同时,GIMP 无疑仍然是使用 GTK+ 的最著名的程序之一,不过它已经不是惟一的使用 GTK+ 的程序了。已经为 GTK+ 编写了成百上千的应用程序,而且至少有两个主要的桌面环境(Xfce 和 GNOME)用 GTK+ 为用户提供完整的工作环境。

GTK+虽然是用C语言写的,但是您可以使用你熟悉的语言来使用GTK+,因为GTK+已经被绑定到几乎所有流行的语言上,如:C++,PHP, Guile,Perl, Python, TOM, Ada95, Objective C, Free Pascal, and Eiffel

使用GTK+的优秀应用程序:

· GIMP-GNU图像处理程序

· GNOME、XFCE等桌面环境和大部分窗口管理器都基于GTK+

· Inkscape-类似于Illustrator、CorelDraw的矢量图形绘制工具

· Pidgin-支持多种协议(IRC、Gtalk、Yahoo Talk、MSN、QQ等等)的聊天工具

· Firefox 、Chrome-两大流行浏览器

· ...

三、Vlc简介

1.简介:

VLC多媒体播放器(英语:VLC media player,最初为VideoLAN Client,是VideoLAN计划的开放源代码多媒体播放器。)支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影音光盘及各类流 协议。它也能作为单播或多播的流服务器在IPv4或IPv6的高速网络连接下使用。调用FFmpeg计划的解码器与libdvdcss程序库使其有播放多 媒体文件及加密DVD影碟的功能。

VLC自建的动态核心模块,使所有的接口(interfaces)、视频和音频输出(video and audio outputs)、控制(controls)、定标器(scalers)、解码器(codecs)、音频/视频滤波器(audio/video filters)包含于统一的模块之内,便于使用。在播放媒体文件时,无需用户干预,VLC会根据不同的情况自行调度输入协议(input protocol)、输入文件的格式(input file format)、输入转码器(input codec)、视频卡功能(video card capabilities)和其他参数。

VLC media player具有跨平台的特性,可用于Linux、Microsoft Windows、Mac OS X、BeOS、OS/2、BSD、安卓、iOS、及Solaris。

2.libvlc

libvlc是VLC media player使用的多媒体框架的核心引擎和扩展编程接口,它可以帮助开发者开发广泛的多媒体应用

libvlc多媒体框架结构如下:

libvlc API关系图表如下:

LibVlc官方API文档

四、gtk构建gtk界面

我们首先也只是布局和添加控件,之后再来实现业务逻辑,不多说,直接看图,这就是我们要先实现的播放器大致的界面布局,不过这个界面将不会是我们最 终要实现的样子,因为这是使用galde界面设计器创建的布局,大家初学时最好不要直接使用glade来进行布局,因为它会忽略很多细节。先从手写代码的 方式进行布局和添加控件,这样有助于你更好的掌握那些控件的使用方法。

1.先了解这个布局的层次关系

window
|---vbox|-------menubar|-------drawingarea|-------hbox
        |---hbuttonbox
        |   |---playbutton
        |   |---stopbutton
        |---scale
        |---fullscreenbutton

2.实现这个布局的代码如下:

//filename:gui.c
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <glib.h> #define BORDER_WIDTH 6 int main(int argc, char* argv[])
{
GtkWidget *window,
*vbox,
*hbox,
*menubar,
*filemenu,
*fileitem,
*filemenu_openitem,
*hbuttonbox,
*player_widget,
*stop_button,
*full_screen_button,
*playpause_button,
*process_scale,
*play_icon_image,
*pause_icon_image,
*stop_icon_image;
GtkAdjustment *process_adjuest; // 每个gtk程序都必须要有的,两个参数对应mian函数的两个参数,用于在命令行执行程序时传递并解析参数
gtk_init(&argc, &argv); // 创建一个window并完成初始化,如设置为顶层窗口,宽度和高度,标题等,并绑定destory信号,以便在关闭gtk窗口后程序能完全退出
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), , );
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), );
gtk_window_set_title(GTK_WINDOW(window), "GTK+ libVLC Demo"); //创建一个方向垂直间距为0的box容器,并添加到前面创建的window中
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, );
gtk_container_add(GTK_CONTAINER(window), vbox); //创建一个menubar和两个menuitem分别为菜单中的“文件”和“打开”,由于它们为上下级菜单关系,
//所以需要单独一个menu来放置"open_menu_item",也就是代码中的filemenu_openitem
menubar = gtk_menu_bar_new();
fileitem = gtk_menu_item_new_with_label ("File");
filemenu_openitem = gtk_menu_item_new_with_label("Open");
filemenu = gtk_menu_new();
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), filemenu_openitem); // 将filemenu设置为上一级fileitem的子菜单,然后将fileitem添加进menubar,最后将menubar放置进vbox
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileitem), filemenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileitem);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, ); //创建一个draw_area控件,用做视频播放显示区域,并放置进vbox
player_widget = gtk_drawing_area_new();
gtk_box_pack_start(GTK_BOX(vbox), player_widget, TRUE, TRUE, ); //创建一个hbox作为vbox的子容器,一个hbuttonbox作为hbox的子容器,hbuttonbox用于放置两个button,
// 再将一个scale(滚动条,用作视频播放进度条,原本的process控件不能拖动)添加进hbox,最后将hbox放置进最外面的vbox
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, );
hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox), BORDER_WIDTH);
gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_START); playpause_button = gtk_button_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON);
stop_button = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(hbuttonbox), playpause_button, FALSE, FALSE, );
gtk_box_pack_start(GTK_BOX(hbuttonbox), stop_button, FALSE, FALSE, );
gtk_box_pack_start(GTK_BOX(hbox), hbuttonbox, FALSE, FALSE, ); //创建一个滚动条,使用一个自定义的adjust对象初始化
process_adjuest = gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00);
process_scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL,process_adjuest);
gtk_box_pack_start(GTK_BOX(hbox), process_scale, TRUE, TRUE, );
gtk_scale_set_draw_value (GTK_SCALE(process_scale), FALSE);
gtk_scale_set_has_origin (GTK_SCALE(process_scale), TRUE);
gtk_scale_set_value_pos(GTK_SCALE(process_scale), );
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, ); // 显示所有控件,并运行gtk程序
gtk_widget_show_all(window);
gtk_main (); return ;
}
 

如果你觉得有困难可以直接下载代码:(以下内容是在实验楼网站的虚拟平台上使用的,没有使用实验楼的不需要下面这个步骤)

$ wget https://raw.githubusercontent.com/shiyanlou/gtk-vlc-video-player/master/gui.c

3.代码说明:

上述代码,使用如下命令编译和运行:

# 注意pgk-config...那里不是单引号,是反单引号$ gcc gui.c -o gui `pkg-config --libs --cflags gtk+-3.0`$ ./gui

运行后,你将看到

代码的解释说明,已经尽可能在注释中说明,代码中一些gtk的API的使用和详细说明,请参看官方API文档,一些API的参数如果不太明确,你可以直接在代码中修改为不同的值,然后编译并运行代码,观察效果,帮助理解.

五、使用libvlc播放媒体文件通过gtk中显示

1.使用libvlc创建一个媒体播放器对象

在mian函数中添加如下代码:

 //setup vlc
vlc_inst = libvlc_new(, NULL);
media_player = libvlc_media_player_new(vlc_inst);
g_signal_connect(G_OBJECT(player_widget), "realize", G_CALLBACK(player_widget_on_realize), media_player);

2.使用filechooserdialog打开一个视频文件

首先给菜单栏中的open添加一个点击信号处理函数on_open,注意一般信号处 理函数的命令规则就是在函数名之前加上"on_",但这不是必需的,然后在on_open这个信号处理函数中,创建一个 filechoosedialog,并运行。打开文件,获取到uri(?)后,将其传递给open_media函数,使用vlc打开并播放视频文件。这里 注意,要想让vlc播放的视频显示在窗口中还需要给之前创建的draw_area控件绑定一个信号处理函数,这里面会将vlc的播放器窗口绘制在控件中。

具体实现代码如下:

添加信号处理

 
// 添加信号处理函数
g_signal_connect(filemenu_openitem, "activate", G_CALLBACK(on_open), window);

处理函数实现

// 信号处理函数
void on_open(GtkWidget *widget, gpointer data) {
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; dialog = gtk_file_chooser_dialog_new("open file", GTK_WINDOW(widget), action, _("Cancel"), GTK_RESPONSE_CANCEL, _("Open"), GTK_RESPONSE_ACCEPT, NULL); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *uri;
uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
open_media(uri);
g_free(uri);
}
gtk_widget_destroy(dialog);
} // 传入视频文件uri,使用libvlc播放视频文件
void open_media(const char* uri) {
media = libvlc_media_new_location(vlc_inst, uri);
libvlc_media_player_set_media(media_player, media); current_play_time = 0.0f;
gtk_scale_set_value_pos(GTK_SCALE(process_scale), current_play_time/video_length*); play();
libvlc_media_release(media);
}
 

因为我们使用了libvlc所以上面代码在编译时需要加上libvlc的编译和链接选项,可使用pkg-config工具获得

比如:$ gcc -o videoplayer videoplayer.c `pkg-config --cflags --libs gtk+-3.0 libvlc`

 

一切正常的话,现在你的播放器应该已经可以播放出视频了,如果你需要一个视频文件来测试播放效果的话,你可以使用我提供的一个视频文件,这是一个相当有趣的视频,所以希望你一定要成功,然后你才能看到这个视频的内容。

$ wget http://anything-about-doc.qiniudn.com/gtk_libvlc_video_player/video_demo_01.flv

六、实现简单的播放控制,暂定/播放和停止

这个比较简单了,就是为播放和停止按钮分别绑定两个点击信号处理函数,并更具当前是否为播放状态设置按钮显示为播放还是暂定,及实现视频的暂定和继续播放

具体代码如下:

同样先添加信号处理

(略)

处理函数实现

// 使用libvlc传入当前的播放器对象,获取播放状态
void on_playpause(GtkWidget *widget, gpointer data) {
if(libvlc_media_player_is_playing(media_player) == ) {
pause_player();
}
else {
play();
}
} void on_stop(GtkWidget *widget, gpointer data) {
pause_player();
libvlc_media_player_stop(media_player);
} // play函数开始播放视频,并将播放按钮的图标换成表示暂定的图标
void play(void) {
libvlc_media_player_play(media_player);
pause_icon_image = gtk_image_new_from_icon_name("media-playback-pause", GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(playpause_button), pause_icon_image);
} void pause_player(void) {
libvlc_media_player_pause(media_player);
play_icon_image = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(playpause_button), play_icon_image);
}

七、实现播放进度显示和拖动进度条跳转

1.视频播放进度的显示

要显示播放进度,可以用两种方式,第一种呢,自定义一个信号每当vlc的播放进度发生变化时就发送这个信号,然后将滚动条绑定该信号,在该信号的信 号处理函数中获取vlc播放进度,并设置为滚动条的值;另一种是添加一个定时器,每隔一个时间比如0.5s去获取vlc的播放进度,使用之前创建滚动条是 自定义的一个GtkAdjuestment对象了设置滚动条的进度。前一种方法比较复杂,这里我们使用后一种

具体代码如下:

在open_media函数中添加定时器

 
// 表示每隔500ms会调用\_update\_scale函数,并将process\_scale作为数据对象传入
g_timeout_add(,_update_scale,process_scale);

_update_scale函数实现

 
// 该函数为一个`GSourceFunc`函数类型,要求必须要有返回值,返回类型为`gboolean`,
// 如要下次继续执行该定时器,须返回`G\_SOURCE\_CONTINUE`,否则返回`G\_SOURCE\_REMOVE`
gboolean _update_scale(gpointer data){
// 获取当前打开视频的长度,时间单位为ms
video_length = libvlc_media_player_get_length(media_player);
current_play_time = libvlc_media_player_get_time(media_player);
gtk_adjustment_set_value(process_adjuest,current_play_time/video_length*);
return G_SOURCE_CONTINUE;
}

2.实现拖动进度条跳转

这个功能可以给scale添加一个value\_changed信号处理函数就可以实现,只是这里有个小问题就是,如果直接这样实现的话,会跟上面的进度显示发生点小冲突,以为上面的进度更新也会触发这里的信号处理函数,导致视频一直在那来回卡动无法正常播放,这里我们可以在更新进度条是使用临时阻塞value\_changed信号的方式避免这个问题

具体代码如下:

添加信号处理(略)

处理函数实现

// 通过adjuest对象获取拖动到的进度数值(根据之前的设定为1-100的范围),
// 然后使用libvlc设定播放位置(根据百分百设定,故要除以100)
void on_value_change(GtkWidget *widget, gpointer data)
{
float scale_value = gtk_adjustment_get_value(process_adjuest);
libvlc_media_player_set_position(media_player, scale_value/);
}

修改_update_scale函数如下:

// 在更新进度条数值前先阻塞信号处理函数的执行,之后在取消阻塞
gboolean _update_scale(gpointer data){
// 获取当前打开视频的长度,时间单位为ms
video_length = libvlc_media_player_get_length(media_player);
current_play_time = libvlc_media_player_get_time(media_player);
g_signal_handlers_block_by_func(G_OBJECT(process_scale), on_value_change, NULL);
gtk_adjustment_set_value(process_adjuest,current_play_time/video_length*);
g_signal_handlers_unblock_by_func(G_OBJECT(process_scale), on_value_change, NULL);
return G_SOURCE_CONTINUE;
}

七、总结


过上面的一些说明,相信你可以独立构建一个实现基本功能的视频播放器了,不过总的说来,它是在是太基础了,简单来讲根本拿不出手啊,作为自己日常 使用都
会有问题,比如不能全屏,不能添加字幕,不能调节音量(抱歉当前我们的实验环境可能也听不到声音,但对于一个播放器来说这一点我们还是要实现)等 等,这
些就请你期待下一节项目课吧,我将带你一步一步添加功能,完善我们的视频播放器

本节完整代码下载(以下内容是在实验楼网站的虚拟平台上使用的,没有使用实验楼的不需要下面这个步骤)

$ git clone https://github.com/shiyanlou/gtk-vlc-video-player.git

更多详细步骤和代码请登录实验楼官方网站:http://www.shiyanlou.com/courses/69

有更多基础课、项目课欢迎大家登陆实验楼官方网站http://www.shiyanlou.com
现在登陆实验楼更有感恩好礼相送http://www.shiyanlou.com/huodong/thanks.html

C语言基于GTK+Libvlc实现的简易视频播放器的更多相关文章

  1. C语言基于GTK+Libvlc实现的简易视频播放器(二)

    简易视频播放器-全屏播放 一.课程说明 上一次我们使用gtk+libvlc实现了一个最简单的视频播放器,可以实现点击按钮暂定和停止播放视频,以及同步显 示视频播放进度,但即使作为一个视频播放器,只有这 ...

  2. 【Harmony OS】【ArkUI】ets开发 简易视频播放器

    ​前言:这一次我们来使用ets的Swiper组件.List组件和Video组件制作一个简易的视频播放器.本篇是以HarmonyOS官网的codelab简易视频播放器(eTS)为基础进行编写.本篇最主要 ...

  3. 简易视频播放器2 (基于Qt、opencv)

    因项目需要,需要实现一个对以保存的监测视频快速查看功能. 查询网上一些资料,初步简易的实现了一下. 实际效果图: 该程序基于Qt5.4,opencv248,开发环境为win8.1 结构为: video ...

  4. 痞子衡嵌入式:基于恩智浦i.MXRT1060的MP4视频播放器(RT-Mp4Player)设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是基于i.MXRT1062的MP4播放器参考设计. i.MXRT1062是恩智浦i.MXRT四位数系列的中端型号,外设搭配上很均衡,辅以6 ...

  5. FFmpeg简易播放器的实现-视频播放

    本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10047035.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  6. FFmpeg简易播放器的实现-音视频同步

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  7. FFmpeg简易播放器的实现-音视频播放

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10235926.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  8. FFmpeg简易播放器的实现-音频播放

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10068490.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  9. FFmpeg简易播放器的实现-最简版

    本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10040202.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

随机推荐

  1. 应用程序框架实战十六:DDD分层架构之值对象(介绍篇)

    前面介绍了DDD分层架构的实体,并完成了实体层超类型的开发,同时提供了验证方面的支持.本篇将介绍另一个重要的构造块——值对象,它是聚合中的主要成分. 如果说你已经在使用DDD分层架构,但你却从来没有使 ...

  2. 1、NoSQL概述

    最近抽时间把Redis学了一下,所以就在网上找了一些资料.然后找到尚硅谷-周阳老师的视频教程,觉得里面的讲的挺好.所以就把他视频当中的资料教程整理出来. 单机MySQL的美好时代 在90年代,一个网站 ...

  3. 十进制(decimal system)转换函数说明

    一,十进制(decimal system)转换函数说明 1,十进制转二进制 decbin() 函数,如下实例 echo decbin(12); //输出 1100 echo decbin(26); / ...

  4. T-Sql(三)存储过程(Procedure)

    今天讲下T-sql语法中存储过程的用法,我们一开始学习数据库语言的时候就是用一些简单的insert,select等语法,但是随着我们学习数据库的深入,就会发现一些简单的语法满足不了我们的要求,比如处理 ...

  5. 数据库SQL Service 2014中文版的安装和配置教程

    一.我的电脑环境 1.windows8.1(64位) 2.之前电脑没有安装数据库的软件 二.装机之前准备(我这儿提供百度云保存和下载) 1.下载一个“Sql service 2014中文版” http ...

  6. SQL SERVER四舍五入你除了用ROUND还有其他方法吗?

    引言 今天和测试沟通一个百分比计算方式时遇到一个问题, 我在存储过程里用到了强转CAST(32.678 AS DECIMAL(5,1))  我认为该方式只会保留一位小数,我给测试的回复是我并没有用到四 ...

  7. tomcat源码剖析系列

    一个简单的web服务器 一个简单的servlet容器 连接器 创建httpRequest 创建HttpResponse 容器 生命周期 日志记录器 载入器 Session管理 关闭钩子 启动tomca ...

  8. 推荐几个Web前端开发实用的Chrome插件

    越来越多的前端开发人员喜欢在Chrome里开发调试代码,Chrome有许多优秀的插件可以帮助前端开发人员极大的提高工作效率.尤其Chrome本身是可以登录的,登录后你所有的插件都会自动同步到每一个登录 ...

  9. ASP.NET Core开发-Docker部署运行

    ASP.NET Core开发Docker部署,.NET Core支持Docker 部署运行.我们将ASP.NET Core 部署在Docker 上运行. 大家可能都见识过Docker ,今天我们就详细 ...

  10. jquery easyui使用(三)······datagrid加载数据(已解决)

    <div id="table_Data"> </div> $("#table_Data").datagrid({ toolbar: '# ...