许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  LS-DYNA中SET_NODE_LIST设置方法:在Matlab GUI中播放带声音的视频(跨领域技巧)

LS-DYNA中SET_NODE_LIST设置方法:在Matlab GUI中播放带声音的视频(跨领域技巧)

阅读数 18
点赞 0
article_banner

992010f939e0b0a3d332f1b836846d96.png

各位同学好,各位知乎的小伙伴们大家好。今天,我要给大家分享的内容是:“如何在Matlab GUI中播放带声音的视频?”

这个问题有点奇怪,什么叫做带声音的视频?视频一般不都是带声音的吗?

没错,一般视频都是带声音的。而且,Matlab是擅长处理视频的,网上找到的教程也确实能够把视频文件读取,处理成一帧一帧的,然后播放出来。但是,问题出在很少有教程把“声音”问题处理好,视频处理成图像逐帧播放却没有声音,让人非常着急。

“没有声音,再好的戏也出不来!”

这个教程会完整地教会大家怎么把视频文件处理好,既能够播放图像,同时也能够播放声音。

我们把整个教程分为六个部分:

(1)读取视频文件(不带声音);

(2)读取视频文件的声音部分;

(3)搭建播放视频的Matlab GUI框架(表面);

(4)实现播放视频的操作;

(5)实现播放声音的操作;

(6)利用跟随变量在一个按钮上实现播放和暂停。

(1)读取视频文件(不带声音)

读取视频文件的标准操作需要用到VideoReader,我们看下面这句代码:


mp4FileName = 'Friends.mp4';mVideo = VideoReader(mp4FileName);

读取后,mVideo这个结构体包含如下变量:

Duration - 视频的总时长(秒)

FrameRate - 视频帧速(帧/秒)

NumberOfFrames - 视频的总帧数

Height - 视频帧的高度

Width - 视频帧的宽度

BitsPerPixel - 视频帧每个像素的数据长度(比特)

VideoFormat - 视频的类型, 如 'RGB24'.

Tag - 视频对象的标识符,默认为空字符串''

Type - 视频对象的类名,默认为'VideoReader'.

UserData - 用户定义的数据,指定为任意数据类型的值,一般默认为“[ ]”

NumberOfFrames - 视频的总帧数。

宽和高信息对于确定窗口和坐标轴控件的属性是有用的,所以一般我们会有意识地把这个变量提取出来:


vWidth = mVideo.Width;vHeight = mVideo.Height;vFrameRate = mVideo.Framerate;

我们还提取了视频帧速这个变量,它可以用来决定播放速度的。

(2)读取视频文件的声音部分

读取视频文件的声音部分需要用到mmread这个工具包,代码示例如下:


[mVar01 mAudio] = mmread(mp4FileName);

这里的问题是mmread不像VideoReader,是Matlab自带的函数,它需要专门做一次“设置路径”的操作。

2e8f9b9f4c6b5e86be964db9f464bdda.png

这个“设置路径”的按钮就在中间的位置,“布局”按钮的右侧,“预设”按钮的下方。点击这个按钮,会弹出一个对话框:

06be3f4833517168e88e16202f229c9b.png

我们采用“添加并包含子文件夹”的方式添加了当前工作目录下面的mmread文件夹,至此,我们就可以利用这个工具包中的mmread函数来读取.mp4文件的音频部分的信息。

(3)搭建播放视频的Matlab GUI框架(表面)


function y = matlabgui_mp4Player(~) % preparemp4FileName = 'Friends.mp4'; mVideo = VideoReader(mp4FileName); % get the info of width and heightvWidth = mVideo.Width * 2; vHeight = mVideo.Height * 2; % create a figurehFigure = figure(1);set(hFigure, 'position',[100 50 vWidth vHeight+100]); % create an axeshAxes = axes('parent',hFigure);set(hAxes, 'units','pixels', 'position',[1 101 vWidth vHeight]); % create a image object, and set its 'parent' propertyhImage = image(readFrame(mVideo), 'parent',hAxes);% % % create a pushbuttonhPushbutton = uicontrol(hFigure, 'Style','pushbutton', 'String','Play', 'position',[1 1 vWidth 100]);   y = hFigure;end

细心的朋友应该注意到了,我把从视频中获取的高度和宽度都乘以了一个系数2,与此同时,我在设置hFigure的时候,在视频高度的基础上增加了一个100,并且坐标轴的高度也上提了100个像素。前者这么操作是因为我们使用的Friends.mp4文件是压缩过的,如果按照正常的比列进行播放的话会非常小,只有220 x 176。后者操作是为了给hPushbutton这个按钮控件留出空间。我们看下最后的布局效果:

da40d1de02fa886903c210b6eaaf83e7.png

大家对看到的黑色有可能产生两种理解,一种是这个黑色是控件默认的颜色,另外一种是这个黑色是读取的视频的第一帧image到坐标轴上的效果。后面这种猜测才是对的!这里关键是对readframe函数的理解。为了更准确地理解这个函数,我们试着用一个循环,假装运行readframe函数200次试试:

77046e7e93d1f2569c272085eee9557f.png

这就验证了第二种理解是正确的。同时,我们大概能够理解,readframe这个函数,运行一次,某个类似指针的用来标记frame的变量会跳到下一帧。有了这个理解,我们就可以人为地设置一个Timer控件,按照视频自身的每秒帧数的节奏播放画面,就可以达到播放视频的效果。

(4)实现播放视频的操作

因为运行一次readframe,指针就会跳到下一帧,这个就为我们播放视频提供了便利。配合Timer控件的使用,我们可以做到收放自如。先定义一个Timer:


% timerglobal t;timePeriod = round(1/vFrameRate,3);t = timer('timerFcn', {@timerFcn, mVideo, hImage}, 'ExecutionMode','Fixedrate', 'Period',timePeriod);

然后要专门写一个它的回调函数timerFcn:


% function --> timerFcn    function timerFcn(obj, ~, v, hIM)        if hasFrame(v)            set(hIM,'cdata',readFrame(v));        else            stop(obj);        end    end

在定义Timer控件的时候,可以利用元胞格式{},往timerFcn函数中传入视频变量(mVideo是实参,v是形参),还有图层句柄(hImage是实参,hIM是形参)。呈现图片用的是set函数,set(hIM,'cdata',readFrame(v))修改hImage句柄的cdata参数就可以把读取的那一帧图像呈现在图层上。

这里用了一个if判断语句,如果还有帧的话,就执行呈现图片的操作;如果没有的话(hasframe函数是用来确定视频变量中的帧是否可供读取),就把obj给停止了。这里的obj就是这个函数的源对象,也就是Timer控件t。因为t是全局变量,所以obj也可以写成stop(t)效果应该是一样的。

(5)实现播放声音的操作

之前通过mmread读取了mp4文件:


[mVar01 mAudio] = mmread(mp4FileName);

但是,这样是不能播放声音的,还需要打造一个mp3player对象:


global mp3player;mp3player = audioplayer(mAudio.data, mAudio.rate, mAudio.bits);

有了这个对象之后,不管是播放play,终止stop,暂停pause,还是恢复播放resume,都可以直接运用在这个对象上。比如,


play(mp3player);

就可以开始播放当前的mp3,也就是从视频中读取的音频部分。

(6)利用跟随变量在一个按钮上实现播放和暂停

作为标题,这么描述有点过于简单了,实际上整个播放包括一开始的启动play,暂停pause,恢复resume和退出后的停止stop。我们会引入一个全局变量叫做mState,它可以标记当前的状态是初始状态0,播放状态2,抑或是暂停状态1,直接粘贴完整版代码(想象一下这时候是有BGM的):


function y = matlabgui_mp4Player(~) % preparemp4FileName = 'Friends.mp4'; % read the video and audio via VideoReader and mmreadmVideo = VideoReader(mp4FileName);[mVar01 mAudio] = mmread(mp4FileName); % get the info. from mVideovWidth = mVideo.width * 2;vHeight = mVideo.height * 2;vFrames = mVideo.NumberOfFrames;vFrameRate = mVideo.Framerate; % prepare mp3player objglobal mp3player;mp3player = audioplayer(mAudio.data, mAudio.rate, mAudio.bits); % create a figurehFigure = figure(1);set(hFigure, 'position',[100 50 vWidth vHeight + 100]);% % create an axeshAxes = axes('parent',hFigure);set(hAxes, 'units','pixels', 'position',[1 101 vWidth vHeight]); % create a image object, and set its 'parent' propertyhImage = image(readFrame(mVideo), 'parent',hAxes);% % % create a pushbuttonhPushbutton = uicontrol(hFigure, 'Style','pushbutton', 'String','Play', 'position',[1 1 vWidth 100]);   % ,  % timerglobal t;timePeriod = round(1/vFrameRate,3);t = timer('timerFcn', {@timerFcn, mVideo, hImage}, 'ExecutionMode','Fixedrate', 'Period',timePeriod); %global mState; mState = 0; % 0 == original vs. 1 == pause vs. 2 == play % assign yy = hFigure; % % Binding  Mechanismset(hPushbutton,'Callback',@hPushbutton_CallbackFcn);set(hFigure, 'DeleteFcn',@hFigure_DeleteFcn);% % function --> hPushbutton_CallbackFcn    function hPushbutton_CallbackFcn(obj, event, hs)        if mState == 0            start(t);            play(mp3player);            set(obj, 'String','Pause');            mState = 2;                    else            if mState == 1                start(t);                resume(mp3player);                set(obj, 'String','Pause');                mState = 2;            else                stop(t);                pause(mp3player);                set(obj, 'String','Resume');                mState = 1;            end                    end     end % function --> timerFcn    function timerFcn(obj, ~, v, hIM)        if hasFrame(v)            set(hIM,'cdata',readFrame(v))        else            stop(obj);        end    end % % % function --> hFigure_DeleteFcn    function hFigure_DeleteFcn(obj, event, hs)            stop(t); delete(t);              stop(mp3player);    end end 

补充一些细节:

(1)一旦我们设定了一个Timer控件,就要记得在退出窗口的时候,把这个timer对象停止并删除。

(2)退出窗口的时候,同样要记得停止mp3player对象,否则窗口关闭之后,声音会一直播放感觉很奇怪。

(3)mState实际上是3种状态,一开始为0,点击按钮就开始播放;播放时为2,点击按钮会出现暂停;进入暂停状态之后为1,点击按钮继续播放。

(4)image和imshow都可以用来把图像矩阵显示在坐标轴上,这里用了image是因为两个原因。第一,它在性能方面是优于imshow的,在这种连续播放图像帧的操作中,肯定会选择性能更优的image函数;第二,是因为image有一个自适应的缩放功能,hAxes在定义时用的是图像矩阵的两倍宽和高,image自动把图像矩阵放大了呈现在坐标轴上。

(5)VideoReader类中的readframe这个操作在2018b版本是会运行报错的,原因是我的这个版本的代码中有一句是这么写的:


vFrames = mVideo.NumberOfFrames;

然后就会报错:


错误使用 VideoReader/readFrame (line 99)不能在查询 NUMBEROFFRAMES 属性或使用 READ 方法后调用'READFRAME' 方法。

这里有两个建议,一个是采用2019b及以上版本,另外一个是注释掉“vFrames = mVideo.NumberOfFrames;”的语句即可。

(6)还有一个很小的细节,就是我们的mp4文件名不能带中文,不然会报错。

到这里,整个教程就写完了。国庆节&中秋节快乐♥

感谢李昌锦和杨轩两位同学的卓越贡献,mmread工具包就是他们找到的。多亏了他们,要不然也不太可能有这么完整的一个教程,♥谢谢谢谢♥


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删


相关文章
技术文档
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空