⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux下的tv播放器.txt

📁 linux下的tv播放器
💻 TXT
📖 第 1 页 / 共 2 页
字号:
 今天就对我实现的linux下的tv播放器进行一个阶段性的总结吧,目前我的这个tv测试程序已经能够实现流畅播放电视,在更改视频帧缓冲设置的情况下录制效果也还不错,并且实现了频道调整和电视频道回放的功能;另外,底层电视库中也增加了亮度、对比度、饱和度、色调调整的代码,以便将来在上层GUI界面中添加对应的设置功能;

这次我先比较详细的说明电视播放和录制的原理和关键代码的实现,两个部分就不拆开了,算作是晚交文章的一个惩罚吧,录制部分就算作是补偿的那一篇啦。
要想弄清楚电视播放和录制的原理,首先得搞清楚电视播放和录制时,数据帧流的流向和数据的存储是如何完成的。
下面我就先介绍一下电视播放时视频帧流的流向:
从视频设备/dev/video采集到得视频数据帧
-->
送到buffer存储
-->
1、(经过YUV420P到RGB32得转换)显示;
2、如果是录制状态,则对视频帧进行压缩,准备存储;同时要从音频设备中/dev/dsp中读取音频数据,我这里采用得是压缩存储,则需要经过mp3压缩,准备存储;
-->
1、显示部分,RGB32格式得视频帧可以直接使用QT得函数进行显示,如果你是采用SDL进行显示,那前面得RGB32格式转换都可以省略了,SDL可以直接显示YUV格式得视频帧;
2、录制状态中,在选定存储得文件格式(比如AVI)后,就进行音频和视频得数据存储了;
电视的播放和录制我想到这里你会有一个大概的数据流的概念了,这样,在以后的编码中就是以此数据流为基础,充分利用计算机的各种已有东西,进行编码实现这种理念;
下面我开始结合具体代码和文件结构进行详细说明:
首先分析几个技术难点,对于视频帧的采集、显示、压缩存储,在录制状态下这几样是同时进行的,这种并行计算在计算机中可以采用线程来实现,(由于进程消耗资源比较大,不可取),这样加上主GUI线程,在录制状态下,同时会有四个线程在运行;
其次,对 于数据帧的存储,我这里采用的方法是使用一个内存视频帧缓冲循环队列,视频帧的显示和录制都是从这个队列当中读取视频帧,而采集视频帧的线程则是将视频帧 写入这个队列中;当然了,这期间需要注意的是尽量使用指针而避免采用大量的内存拷贝操作,以便提高性能;至于具体如何操作,后面会进行详述;
最后,在视频进行全屏的实现过程中,至少要经过三个步骤--对视频帧进行全屏大小的转换,进行YUV到RGB32的格式转换,最后进行GUI界面刷屏显示;这三个步骤中前两步是比较耗资源的,我现在实现的tv测试程序,仍然不能够很好的解决电视在进行全屏播放的视频帧刷新缓慢问题,这也是当前的一个突出的难点;
有关这个问题的解决方案,我目前是打算参考mplayer的实现全屏的方法,只是mplayer全屏实现代码太散,目前还没有找到;
好,下面我先说说我的测试程序的文件夹结构,整个程序包括以下几个文件夹--bin、common、doc、gui、hdware、interface、image,最主要的是gui、hdware和interface三个文件夹中的东西,顾名思义,gui主要包含了和界面显示以及tv视频帧显示的代码部分,而hdware则是与硬件相关比较紧密的部分,我在这里放了电视的底层实现库,interface则是gui和hdware之间的接口部分,主要是线程的C++实现和缓冲类以及需要的几个线程类的代码;
文件结构如下图所示:

// ------------------------------------------------

# ls gui

Qtgui // 之所以有这个qt的gui文件夹,是因为以后可能还需要写其他界面的界面部分,所以这里留出扩展的余地,以方便将来进行扩展;

# find gui/qtgui

gui/qtgui/

gui/qtgui/mainwindow.cpp // 主窗口类文件;

gui/qtgui/mainwindow.h

gui/qtgui/mainwindow.moc

gui/qtgui/tvwindow.moc // 显示tv的窗口类;

gui/qtgui/tvwindow.cpp

gui/qtgui/tvwindow.h

gui/qtgui/mainwindow.o

gui/qtgui/tvwindow.o

gui/qtgui/main.cpp // 主函数;

gui/qtgui/Makefile

gui/qtgui/qttv.o

gui/qtgui/qtwindow.a // 打包成库;

// ------------------------------------------------

# ls hdware

video

# ls hdware/video/tv

hdware/video/tv/

hdware/video/tv/tv.bak.c

hdware/video/tv/tv.c // tv底层实现库;

hdware/video/tv/tv.h

hdware/video/tv/tv.o

hdware/video/tv/Makefile

hdware/video/tv/tv.a // 打包成库;方便以后将这部分单独拿出来独立成库;

// ------------------------------------------------

# find interface

interface/

interface/thread

interface/thread/Makefile

interface/thread/mthread.cpp // 一个C++封装的线程类,使用方法类似java中的线程类;

interface/thread/mthread.o

interface/thread/thread.a // 打包成库;

interface/thread/mthread.h

interface/Makefile

interface/tvgrabthread.cpp // 从mthread类继承,实现采集视频功能;

interface/tvgrabthread.h

interface/tvgrabthread.o

interface/tvrecordthread.o

interface/tvrecordthread.cpp // 从mthread类继承,实现录制视频功能;

interface/tvrecordthread.h

interface/tvthread.a // 打包成库;

interface/buffer

interface/buffer/videobuffer.o

interface/buffer/videobuffer.h

interface/buffer/Makefile

interface/buffer/buffer.a // 打包成库;

interface/buffer/videobuffer.cpp // 视频帧缓冲类;

其实看了这些,我想你对具体那一部分是做什么的,以及如何编写已经有了大概的认识了,下面我会对一些关键点进行具体的说明;

一共两个关键点--播放和录制;

具体涉及到的技术点一共有四个,分别是:采集视频帧线程、显示视频帧线程、录制视频帧线程、视频帧缓冲队列;
下面我就分别针对这几个技术关键点进行详细说明;

电视播放--

采集视频帧线程

视频帧采集采用线程实现的原因是为了能够提高GUI界面的响应速度,这一点我想大家都是毋庸置疑的。
详细描述:
此线程主要完成从Linux下视频设备/dev/video中读取视频帧,并将其保存在视频帧队列中(详情请看下一条说明);本线程是继承自一个线程类, 这个线程类是自己编写的,特性和使用方法都可以参考java中的线程类;因此,本线程最关键的地方也就是重新实现线程的run方法,这里我将run中关键 代码贴出来,并把加上详细注释;
Void LtvGrabThread::run(){
    //
AVFrame *pf_frameYUV420P = NULL;
    // Allocate video frame
    pm_frame = avcodec_alloc_frame();
    pm_frame_YUV420P = pm_frame;
    // Read frames
    while ( m_tv_playing_flag ){
        // while tv is playing, read one frame from packets;
        if ( av_read_frame (pm_format_context, &f_packet) < 0 ){
            continue;
        }
        // Is this a packet from the video stream?
        if (f_packet.stream_index == m_video_stream)
        {
            // Decode video frame
            avcodec_decode_video (pm_codec_context, pm_frame,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -