JCHub

  • Home
  • Category
    • A/V
    • WebRTC
    • Beauty of Programming
    • Linux
    • Windows
    • Moments of Life
    • Campus Life
  • Reference
    • API Reference
    • Utilities
    • AV Test
    • Doc
  • Message Board
  • About
A/V
A/V

VLC播放h264头几秒花屏问题

原来测试解析mp4文件得到的h264码流都是用ffplay,没遇到什么问题,今天用vlc测试了下,发现刚开始时会有点花屏,后面就正常了。 看了下h264码流,sps与pps后第一个nalu类型为sei(附加增强信息),也就是0x00000106起始码开头的,不是I帧,所以会出现这个情况。vlc没有对sei信息做处理,导致把sei与后面数据混在一起解码处理,出现丢数据的假象,而导致花屏。vlc处理首帧的正确姿势是:SPS+ PPS + I frame。后面碰到sei类型nalu数据直接丢掉,然后送给vlc播放,就正常了。后面又测了其他mp4文件,发现这些mp4文件mdat box存储的第一个nalu类型都为sei。所以可以采取丢掉sei,读取完SPS+PPS后送给vlc后,跳过sei,从I帧开始继续送给vlc播放就可以避免播放出现花屏。

2016年5月5日 0comments 3908hotness 15likes Jeff Read all
A/V

移动直播技术秒开优化经验(转)

说明:本文转自@高可用架构,写的很详细,故拿来分享 作者:徐立,七牛创始合伙人兼产品副总裁,负责七牛直播云的整体研发,是国内 Go / Docker / Container 技术早期布道者,Go / Containers / Distributed Systems 技术的忠实爱好者和实践者。曾合著国内第一本 Go 语言图书《Go 语言编程》,翻译《Go 语言程序设计》。 现今移动直播技术上的挑战要远远难于传统设备或电脑直播,其完整的处理环节包括但不限于:音视频采集、美颜/滤镜/特效处理、编码、封包、推流、转码、分发、解码/渲染/播放等。 直播常见的问题包括: 主播在不稳定的网络环境下如何稳定推流? 偏远地区的观众如何高清流畅观看直播? 直播卡顿时如何智能切换线路? 如何精确度量直播质量指标并实时调整? 移动设备上不同的芯片平台如何高性能编码和渲染视频? 美颜等滤镜特效处理怎么做? 如何实现播放秒开? 如何保障直播持续播放流畅不卡顿? 本次分享将为大家揭开移动直播核心技术的神秘面纱。 视频、直播等基础知识 什么是视频? 首先我们需要理解一个最基本的概念:视频。从感性的角度来看,视频就是一部充满趣味的影片,可以是电影,可以是短片,是一连贯的视觉冲击力表现丰富的画面和音频。但从理性的角度来看,视频是一种有结构的数据,用工程的语言解释,我们可以把视频剖析成如下结构: 内容元素 ( Content ) 图像 ( Image ) 音频 ( Audio ) 元信息 ( Metadata ) 编码格式 ( Codec ) Video : H.264,H.265, … Audio : AAC, HE-AAC, … 容器封装 (Container) MP4,MOV,FLV,RM,RMVB,AVI,… 任何一个视频 Video 文件,从结构上讲,都是这样一种组成方式: 由图像和音频构成最基本的内容元素 图像经过视频编码压缩格式处理(通常是 H.264) 音频经过音频编码压缩格式处理(例如 AAC) 注明相应的元信息(Metadata) 最后经过一遍容器(Container)封装打包(例如 MP4),构成一个完整的视频文件。 如果觉得难以理解,可以想象成一瓶番茄酱。最外层的瓶子好比这个容器封装(Container),瓶子上注明的原材料和加工厂地等信息好比元信息(Metadata),瓶盖打开(解封装)后,番茄酱本身好比经过压缩处理过后的编码内容,番茄和调料加工成番茄酱的过程就好比编码(Codec),而原材料番茄和调料则好比最原本的内容元素(Content)。 视频的实时传输 简而言之,理性的认知视频的结构后,有助于我们理解视频直播。如果视频是一种“有结构的数据”,那么视频直播无疑是实时传输这种“有结构的数据”(视频)的方式。 那么一个显而易见的问题是:如何实时(Real-Time)传输这种“有结构的数据”(视频)呢? 这里边一个悖论是:一个经过容器(Container)封装后的视频,一定是不可变的 ( Immutable ) 视频文件,不可变的 ( Immutable ) 的视频文件已经是一个生产结果,根据“相对论”,而这个生产结果显然不可能精确到实时的程度,它已经是一段时空的记忆。 因此视频直播,一定是一个 “边生产,边传输,边消费”的过程。这意味着,我们需要更近一步了解视频从原始的内容元素 ( 图像和音频 ) 到成品 ( 视频文件 ) 之前的中间过程 ( 编码 )。 视频编码压缩 不妨让我们来深入浅出理解视频编码压缩技术。 为了便于视频内容的存储和传输,通常需要减少视频内容的体积,也就是需要将原始的内容元素(图像和音频)经过压缩,压缩算法也简称编码格式。例如视频里边的原始图像数据会采用 H.264 编码格式进行压缩,音频采样数据会采用 AAC 编码格式进行压缩。 视频内容经过编码压缩后,确实有利于存储和传输; 不过当要观看播放时,相应地也需要解码过程。因此编码和解码之间,显然需要约定一种编码器和解码器都可以理解的约定。就视频图像编码和解码而言,这种约定很简单: 编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures ) , 解码器在播放时则是读取一段一段的 GOP 进行解码后读取画面再渲染显示。 GOP ( Group of Pictures ) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器和解码器存取的基本单位,它的排列顺序将会一直重复到影像结束。 I 帧是内部编码帧(也称为关键帧),P 帧是前向预测帧(前向参考帧),B 帧是双向内插帧(双向参考帧)。简单地讲,I 帧是一个完整的画面,而 P 帧和 B 帧记录的是相对于 I 帧的变化。 如果没有 I 帧,P 帧和 B 帧就无法解码。 小结一下,一个视频 ( Video ) ,其图像部分的数据是一组 GOP 的集合, 而单个 GOP 则是一组 I / P / B 帧图像的集合。 在这样的一种几何关系中,Video 好比一个 “物体”,GOP 好比 “分子”,I / P / B 帧的图像则好比 “原子”。 想象一下,如果我们把传输一个 “物体”,改成传输一个一个的 “原子”,将最小颗粒以光速传送,那么以人的生物肉眼来感知,将是一种怎样的体验? 什么是视频直播? 不难脑洞大开一下,直播就是这样的一种体验。视频直播技术,就是将视频内容的最小颗粒 ( I / P / B 帧,…),基于时间序列,以光速进行传送的一种技术。 简而言之,直播就是将每一帧数据 ( Video / Audio / Data Frame ),打上时序标签 ( Timestamp ) 后进行流式传输的过程。发送端源源不断的采集音视频数据,经过编码、封包、推流,再经过中继分发网络进行扩散传播,播放端再源源不断地下载数据并按时序进行解码播放。如此就实现了 “边生产、边传输、边消费” 的直播过程。 理解以上两个关于 视频 和 直播 两个基础概念后,接下来我们就可以一窥直播的业务逻辑了。 直播的业务逻辑 如下是一个最精简的一对多直播业务模型,以及各个层级之间的协议。 各协议差异对比如下 以上就是关于直播技术的一些基础概念。下面我们进一步了解下影响人们视觉体验的直播性能指标。 影响视觉体验的直播性能指标 直播第一个性能指标是延迟,延迟是数据从信息源发送到目的地所需的时间。 根据爱因斯坦的狭义相对论,光速是所有能量、物质和信息运动所能达到的最高速度,这个结论给传播速度设定了上限。因此,即便我们肉眼感觉到的实时,实际上也是有一定的延迟。 由于 RTMP/HLS 是基于 TCP 之上的应用层协议,TCP 三次握手,四次挥手,慢启动过程中的每一次往返来回,都会加上一次往返耗时 ( RTT ),这些交互过程都会增加延迟。 其次根据 TCP 丢包重传特性,网络抖动可能导致丢包重传,也会间接导致延迟加大。 一个完整的直播过程,包括但不限于以下环节:采集、处理、编码、封包、推流、传输、转码、分发、拉流、解码、播放。从推流到播放,再经过中间转发环节,延迟越低,则用户体验越好。 第二个直播性能指标卡顿,是指视频播放过程中出现画面滞帧,让人们明显感觉到“卡”。单位时间内的播放卡顿次数统计称之为卡顿率。 造成卡顿的因素有可能是推流端发送数据中断,也有可能是公网传输拥塞或网络抖动异常,也有可能是终端设备的解码性能太差。卡顿频次越少或没有,则说明用户体验越好。 第三个直播性能指标首屏耗时,指第一次点击播放后,肉眼看到画面所等待的时间。技术上指播放器解码第一帧渲染显示画面所花的耗时。通常说的 “秒开”,指点击播放后,一秒内即可看到播放画面。首屏打开越快,说明用户体验越好。 如上三个直播性能指标,分别对应一个低延迟、高清流畅、极速秒开 的用户体验诉求。了解这三个性能指标,对优化移动直播 APP 的用户体验至关重要。 那么移动直播场景下具体而言有哪些常见的坑呢? 根据实践总结下来的经验,移动平台上视频直播的坑主要可以总结为两方面:设备差异,以及网络环境这些场景下带来的技术考验。 移动直播场景的坑与规避措施 不同芯片平台上的编码差异 iOS 平台上无论硬编还是软编,由于是 Apple 一家公司出厂,几乎不存在因为芯片平台不同而导致的编码差异。 然而,在 Android 平台上,Android Framework SDK 提供的 MediaCodec 编码器,在不同的芯片平台上,差异表现很大, 不同的厂家使用不同的芯片,而不同的芯片平台上 Android MediaCodec 表现略有差异,通常实现全平台兼容的成本不低。 另外就是 Android MediaCodec 硬编层面的 H.264 编码画质参数是固定的…

2016年4月29日 0comments 2058hotness 0likes Jeff Read all
A/V

flv文件adts头计算

常见flv文件封装的音频用的都是aac编码,aac文件有两种格式,一个是AIDS,一个是ADTS(Audio Data Transport Stream 音频数据传输流)。其中ADTS格式用于流式传输,因为每一帧都包含头信息,可以从任一帧开始解码,故用于流式传输。本文主要讲下flv文件中的adts。 adts的头部结构 adts头部大小7个字节或者9个字节(决定于是否包含CRC)。结构定义如下图所示: MPEG-4 Audio Object Type 0: Null 1: AAC Main 2: AAC LC (Low Complexity) 3: AAC SSR (Scalable Sample Rate) 4: AAC LTP (Long Term Prediction) 5: SBR (Spectral Band Replication) 6: AAC Scalable 7: TwinVQ 8: CELP (Code Excited Linear Prediction) 9: HXVC (Harmonic Vector eXcitation Coding) 10: Reserved 11: Reserved 12: TTSI (Text-To-Speech Interface) 13: Main Synthesis 14: Wavetable Synthesis 15: General MIDI ······ MPEG-4 Sampling Frequency Index 0: 96000 Hz 1: 88200 Hz 2: 64000 Hz 3: 48000 Hz 4: 44100 Hz 5: 32000 Hz 6: 24000 Hz 7: 22050 Hz 8: 16000 Hz 9: 12000 Hz 10: 11025 Hz 11: 8000 Hz 12: 7350 Hz 13: Reserved 14: Reserved 15: frequency is written explictly MPEG-4 Channel Configuration 0: Defined in AOT Specifc Config 1: 1 channel: front-center 2: 2 channels: front-left, front-right 3: 3 channels: front-center, front-left, front-right 4: 4 channels: front-center, front-left, front-right, back-center 5: 5 channels: front-center, front-left, front-right, back-left, back-right 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel 8-15: Reserved flv文件获取AudioSpecificConfig 在flv文件中,上述Audio Object Type,Channel Configrartion等信息存储在AudioSpecificConfig结构中,该AudioSpecificConfig结构一般存储在第一个Audio Tag数据中。在ISO 14496-3中AudioSpecificConfig结构按如下定义: 也就是: [crayon-69c7095ded531140641111/] 如下图所示,我们打开一个音频为aac编码的flv视频文件(本文讨论的都是aac编码的),红色框处是tag data部分数据: 由flv标准文档AudioData定义可知,Audio Tag data部分第一个字节(0xAF)结构如下: 接着一个字节为AACPacketType(0x00): 第一个Audio Tag只包含头信息,不包含具体音频数据,所以AACPacketType值为0。Audio Tag data剩余的才是真正adts帧数据,也就是要把Audio Tag data除去前两个字节。到这里,我们得到了AudioSpecificConfig数据为:0x13 0x88 0x56 0xE5 0xA5 0x48 0x80。在程序中我们先构造一个字符数组,用于存储该数据: [crayon-69c7095ded53d618475882/] 从flv文件中读取Audio Tag data除去前两个字节的数据: [crayon-69c7095ded541392860082/] 解析AudioSpecificConfig 由前一部分得知AudioSpecificConfig按如下解析: [crayon-69c7095ded544686045474/] 通过位操作得到相应信息,代码如下: [crayon-69c7095ded548166233659/] 程序中得到的3个数据我们将在下一部分使用。 计算adts头部 这里我们只讨论adts头部为7个字节的,首先构造一个字符数组存储adts头部: [crayon-69c7095ded54b216571510/] 接着计算得到flv文件所有adts帧头部相同部分: [crayon-69c7095ded54e214794512/] 接下来要计算的数据跟每一个adts帧长度有关,是变化的。如下所示是flv tag的结构,在flv每个tag中,数据部分长度为datasize(tagheader_datasize)。 由前面可知flv中Audio Tag存储的真实adts帧数据长度为tagheader_datasize - 2,此时还要加上7个字节adts头部长度才是完整一帧 adts长度,我们设置该长度为: [crayon-69c7095ded552140173708/] 然后根据该AdtsLen计算得到头部剩下几位: [crayon-69c7095ded555196517773/] 至此我们可以得到了每一帧7个字节的adts头部,加上每一个adts帧的数据,可以得到完整的adts文件。 参考文档 1.flv标准说明video_file_format_spec_v10.pdf:https://pan.baidu.com/s/1z8RSGdQ_wzeXf8J50JMEQA 2.ISO/IEC 14496-3ISO_IEC_14496-3.PDF:https://pan.baidu.com/s/1TNrwlSshmDM3ZcglPHlHCA

2016年4月29日 0comments 3271hotness 3likes Jeff Read all
A/V

libVLC SDK下载地址

以前在Windows下使用libVLC 时都是直接到官网下VLC安装包,安装后目录下有个SDK文件夹。最近要用到新版的SDK,安装完最新VLC后没看到目录下有SDK文件夹。后来找了下,在另一个地方可以下载到。 下载地址:http://download.videolan.org/pub/videolan/vlc/ 在这个地址可以下载到各个版本的VLC,点击进入某个版本,下载windows下7z格式压缩包,解压即可得到相应的SDK。

2016年4月15日 0comments 3303hotness 17likes Jeff Read all
A/V

avcodec_decode_video2解码得不到图像

如下所示代码: [crayon-69c7095dee96d627835021/] 在使用avcodec_decode_video2函数解码时经常会遇到frameFinished == 0,也就是无法得到一帧解码后的图像。有些人可能会怀疑是哪里出错了,其实这是正常的现象,ffmpeg内部解码时做了处理。处理如下: 1)该帧为B帧,由于B帧是前后参考帧,需要结合前面的I帧或者P帧,以及后面的P帧来生成完整图像,所以该帧如果是B帧,就无法立即解码,所以返回的frameFinished为0,需要解码完后一帧后才可以解码该帧; 2)缓存处理,解码器解码时会缓存几帧提高程序的效率,防止程序在解码这一步等待太久。当解码到最后av_read_frame没有返回新的packet时,由于解码器存在缓存,所以最后我们需要清空解码器,通过传入空的packet给avcodec_decode_video2,直到没有新的解码后的frame返回这一方法来清空解码器。

2016年4月8日 0comments 3011hotness 10likes Jeff Read all
A/V

MP4解析得到的视频播放问题

前段时间完成了AVI的文件解析程序,也封装了接口。这段时间一直在写MP4文件的解析程序(都没用到第三方库),已经写得差不多了,可以还原音视频帧列表,得到封装的音视数据。不过在测试播放解析得到的视频却发现了一个问题,部分MP4文件解析得到的视频可以用ffplay播放,部分不行。后来仔细对比了下视频文件内容,发现是视频编码类型导致的。 解析后的视频数据不做处理,写到文件可以直接播放的mp4文件视频编码格式为MPEG4,每一帧头部是0x00 0x00 0x01分隔符。 而编码格式为H264的sample数据区别于一般的NALU,此时mdat box中sample格式定义为:4字节sample长度+数据,也就是startcode是4字节长度,不是0x00 0x00 0x00 0x01。 所以我们要得到符合H264标准的数据,需要将sample头部4字节长度替换为0x00 0x00 0x00 0x01分隔符,这样就得到了一个完整的nalu。 SPS、PPS、I帧(包含一个或多个 I-Slice)、P帧(包含一个或多个P-Slice)、B帧(包含一个或多个 B-Slice)构成典型的 H.264 码流结构。要想让解码器解码,我们还必需sps与pps这两个参数集。sps与pps数据从stsd box得知,如下图。然后我们在获取的sps与pps数据头部加上0x00 0x00 0x00 0x01构成一个完整的nalu,这样就得到了sps或pps类型的nalu。

2016年3月15日 4comments 4913hotness 2likes Jeff Read all
A/V

AVI文件详细解析

最近在做视频文件的解析,需要将视频文件中封装的视频与音频解析出来,然后用自己的解码器解码。这个过程专业点叫做叫做Demultiplex,视频播放器中负责这部分的叫做Demuxer。我们平时看到的各种格式视频,比如:avi,mp4,mkv等相当于一种容器,里面包含了音视频,字幕的信息以及数据,Demuxer的工作就是解析视频文件,取出里面的音视频或者字幕送到指定的解码器解码。 我刚开始接触的avi文件的解析。首先介绍下AVI文件。AVI英文全称为Audio Video Interleaved,即音视频交错格式,AVI基于RIFF文件结构。 一.基本数据单元 在AVI中有两种最基本的数据单元,一个是chunk,一个是list。这两种结构如下: [crayon-69c7095def1f6513429858/] 可知chunk由三部分组成:4字节的标记ID,4字节大小(指数据大小),以及数据。 list由四部分组成,4字节“list”,4字节大小(指后面两部分),4字节列表类型,数据。 二.AVI文件类型 1.AVI 1.0 最基本的格式,由于索引地址与大小用4字节表示,所以最大支持4G容量,而且与文件系统类型有关,如下: --Video for Windows (AVI 1.0) -FAT (FAT16): 4 GB (2 GB practical, safe) -FAT32: 4 GB (2 GB practical, safe) -NTFS: 4 GB (2 GB practical, safe) 为了安全一般限制为2G(参考链接1) 2.AVI 2.0(Open—DML) AVI的扩展格式,解决AVI 1.0大小限制(AVI2.0详细资料见参考链接2) 本文主要讨论AVI 1.0,AVI2.0解析后续再做研究。 三.AVI结构 一个AVI文件通常有如下几个子块组成: 1)ID为"hdrl"的list,包含了音视频信息,描述媒体流信息 2)ID为"info"的list,包含编码该AVI的程序信息 3)ID为"junk"的chunk,都是些无用的数据 4)ID为"movi"的list,包含了交错排列的音视频数据 5)ID为"idxl"的chunk,包含音视频排列的索引数据(可选块) 四.详细解析 1.RIFF文件头 用UltraEdit(或者其他文本编辑器)打开一个AVI文件(本文分析用到的avi文件下载地址) 可以看到前4个字节为"RIFF",接着4字节RIFF文件大小(0x01811050即25235536字节,因为AVI文件以小端方式存储数据),再接着4字节为RIFF文件类型"avi" 2.hdrl列表 1)hdrl list头部 可以看到接下来为hdrl list。首先是4字节的"list",然后4字节list大小,接着是4字节list类型"hdrl"。 2)avih块 用于描述主信息头。 4字节的"avih"标识,4字节大小(0x38即56),接下来是56个字节数据。该块可以用如下结构体表示: [crayon-69c7095def1ff552088017/] 3)strl list头部 一个strl list中至少包含一个strh块和一个strf块。文件中有多少个流,就对应有多少个strl list。 上图可知依次为4字节"list",4字节的list大小,4字节"strl"标识。 4)strh块 用于描述流的头信息。 4字节"strh",4字节"strh"块大小(0x38即56),后面是56字节大小数据。该块用如下结构体表示: [crayon-69c7095def203558219537/] 5)strf块 该块用于描述流的具体信息。如果是视频流(vids,由strh块得知),用一个BitmapInfo结构体表示,如果是音频流(auds),用WaveFormatEx结构体表示。 [crayon-69c7095def206585382471/] 该块首先4字节"strf"标识,4字节大小0x28即40,接着的数据用一个40字节大小的BitmapInfo结构体表示。 6)strd块与strn块 strd:可选的额外的头信息数据 strn:可选的流的名字 这两个块是可选的,本AVI文件不包含,故不分析。 7)strl list 由于该AVI文件有两个流,所以有两个strl list。该strl list用于描述音频流信息。具体分析同上。 3.info list 该list用于描述编码该AVI文件的程序信息,包含一个isft块。 4.junk块 该块都是一些垃圾填充数据,用于内部数据的队齐(填充),直接跳过。 5.movi list 该list存储音视频数据块,音视频数据块在该list中交错方式存放着。 movi lst中音视频数据子块的种类有:##db,##dc,##pc,##wb。 --##表示数据所属的流的序号(由于第一个流是视频(第一个hdrl list描述视频),故音频用01wb表示,视频用00dc或00db) --db:未压缩的视频帧 --dc:压缩的视频帧 --wb:音频数据 --pc:改用新的调色板 6.idx1块 该块是可选的,描述音视频数据的索引块信息。索引块可用如下结构体表示: [crayon-69c7095def209939585905/] 在AVIMainHeader的dwFlags中指出是否包含索引块。有了索引块可以方便文件快进,如果没有索引块,在对AVI进行快进时需要计算位置,会很耗时。 五.程序编写 通过如上分析对AVI结构有了清楚了解。在这基础上自己写了个AVI解析程序,可以解析AVI1.0格式文件,同时生成对应的视频与音频文件。 我用ffmpeg自带的ffplay测试解析生成的h264视频文件,可以正常播放。 参考链接 1)http://www.myvideoproblems.com/Tutorials/dv-aviFiles.htm 2)odmlff2.pdf:https://pan.baidu.com/s/1CXiargLfspQwaWoRYjqHqw 提取码: haj8

2016年2月23日 7comments 7229hotness 3likes Jeff Read all
A/V

使用libVLC实现的播放器:支持双击全屏

背景 最近在学习duilib这个库,看了网上Alberl的教程,他那个仿迅雷播放器做的不错,我就直接拿来学习duilib了。不过这个播放器有个缺点,就是无法双击全屏,也就是鼠标放到libVLC播放窗口时无法响应消息,消息都被libVLC内部处理了。这对我们而言不是很方便。因为有时我们需要双击全屏,或者弹出鼠标右键菜单做一些操作。后来上网查了下,好多人遇到这个问题。下面是一些查到的解决方法。 解决libVLC无法响应鼠标消息 如下是查到的一些方法: 1)使用全局钩子; 2)修改libVLC鼠标消息处理代码,重新编译; 3)禁用子窗口消息。 第一种方法不安全,容易被杀毒软件干掉,而且效率不高,第二种方法麻烦,编译就得花你好多时间,而且很麻烦,第三种方法比较简单,解决方法如下: [crayon-69c7095df04e1809671235/] 具体实现见下面。 基于duilib实现 duilib学起来还是很容易上手的,这里我的代码是基于Alberl的仿迅雷播放器。最后实现的界面如下: 按照上面的解决方法,在这个程序中我是这么解决无法响应消息的: 1)当开始播放某个文件后,创建一个一秒的定时器(也可以不创建,直接跳到直接第二步,创建定时器是为了确保我们处理时VLC窗口已经生成); [crayon-69c7095df04ea729480995/] 2)在定时器的回调函数中枚举得到VLC创建的窗口的句柄,通过spy++可以了解到libVLC创建的播放窗口名为:VLC video output,获取到VLC窗口的句柄后使用EnableWindow函数禁用掉键鼠输入,EnableWindow函数的作用是允许/禁止指定的窗口或控件接受鼠标和键盘的输入,代码如下: [crayon-69c7095df04ee599854299/] 通过如上方法,在VLC播放窗口上的鼠标键盘消息我们都可以获得,这样就可以去实现自己想要的功能。比如我在全屏时响应WM_MOUSEMOVE消息,实现底部播放面板自动隐藏。双击全屏也很简单,当响应双击消息时,只显示作为libvlc父窗口那个控件,其他控件都隐藏即可。整个播放器的代码我已经上传到Github。 地址:https://github.com/yjfxfjch/JCHPlayer 我是用的是VS2015编译,低版本VS可能无法直接打开编译。下面一节是使用MFC做界面实现的版本。 基于MFC实现 1)在MFC对话框程序中,首先添加一个控件,这里我添加了一个Picture Contron:IDC_PLAYWND; 2)获得IDC_PLAYWND控件句柄; [crayon-69c7095df04f2947188737/] 3)让libVLC播放对象设置gPlayHwnd 为播放窗口句柄,这样libVLC播放窗口就成为IDC_PLAYWND控件的子窗口; [crayon-69c7095df04f5253128932/] 4)开始播放后创建一个定时器(也可以不创建,直接EnableWindow相应窗口句柄); [crayon-69c7095df04f8644524885/] 5)定时器回调函数以及处理过程如下: [crayon-69c7095df04fb344779907/] 在上述代码中,我们通过之前得到的IDC_PLAYWND控件句柄枚举得到子窗口VLC播放窗口句柄,接着通过EnableWindow函数禁止VLC播放窗口接受鼠标键盘输入。这时我们的程序就可以响应鼠标点击libVLC播放窗口的消息了; 6)设置全屏,主要是设置IDC_PLAYWND控件全屏时占满整个屏幕,然后隐藏其他控件以及标题栏,这样VLC子窗口就可以全屏播放了。不需要使用libvlc_set_fullscreen这个内置api,使用这个api无法达到效果。 最后实现的简单版本如下: MFC版本支持双击全屏的libvlc播放器代码我也上传到Github,具体的可以去看下。 Github地址:https://github.com/yjfxfjch/SimpleVlcPlayer

2015年11月23日 15comments 11034hotness 12likes Jeff Read all
12345
Copyright Statement

Unauthorized reproduction or plagiarism in any form is strictly prohibited. For reprint requests, please contact via email.

Recent Comments
snail Published at 13 hours ago(03 03202633105 27 27pm26) 多谢,大佬。醍醐灌顶!
Bramsnawl Published at 20 hours ago(03 03202633110 27 27am26) Proper blood collection playing cards are measure ...
NasibDepdrotte Published at 1 days ago(03 03202633110 26 26pm26) Inf ect isC linNo rth A m viiiix, Sm ets o urgo is...
Pereplanirovka kvartir_cvsr Published at 3 days ago(03 03202633105 25 25pm26) перепланировка услуги [url=https://pereplanirovka-...
Mirzoemele Published at 3 months ago(01 01202613104 06 06pm26) Double blind randomised controlled trial of two to...
Ad

COPYRIGHT © 2026 jianchihu.net. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang