在Linux下播放与录制电视

最近,在自己的Debian 7.2 64位系统上成功安装了圆刚AverMedia C725B视频卡驱动。于是,可以使用mplayermencoder来看电视与录节目了。其中,用于播放电视的命令如下:

 

mplayer tv:// -tv driver=v4l2:device=/dev/video0:norm=PAL:alsa:adevice=hw.2,0:amode=1:audiorate=48000:forceaudio:volume=100:immediatemode=0:normid=8:input=1:buffersize=1024:width=768:height=576:outfmt=i420 -vo xv -ao sdl -aspect 4:3

 

 

但该命令存在的问题时,当电视播放一段时间后视频与音频便不再同步。

录制节目则可以用mencoder来实现:

 

mencoder tv:// -tv driver=v4l2:device=/dev/video0:norm=PAL:alsa:adevice=hw.2,0:amode=1:audiorate=48000:forceaudio:volume=100:immediatemode=0:normid=8:input=1:buffersize=64:width=720:outfmt=yuy2
-oac mp3lame -lameopts fast:preset=standard -ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=1800 -o output.avi

 

 

上面两条命令虽然能用,但却无法实现电视节目的边放边录。通过网上的搜索(参考)和自己的测试,电视的录制与同时播放可以采用命名管道+tee+mplayer来实现。为了方便操作,写了一个脚本程序rtv,其可用三种模式运行:

  • watch:在播放电视的同时,将其存为avi文件。

  • nowatch:只录制节目不用mplayer播放。

  • onlywatch:只用mplayer看节目而不录制。

脚本首先检测用户的命令行参数输入,然后查看是否已有mencoderteemplayer进程运行。若存在,则不再执行后面的部分;否则,执行如下的流程:

  1. 首先,使用mkfifo创建命名管道;

  2. 其次,用tee命令读取管道:在录制与播放的模式下(watch)将其分为两路,一路送至avi文件,一种送至mplayer用于播放;在只录制不播放的模式下(nowatch),只输出至avi文件;在纯播放模式下(onlywatch),只送至mplayer

  3. 最后,用mencoder/dev/video0截取视频流并输出到之前创建的命名管道。

rtv脚本内容如下:

 

#!/bin/bash 

# Define a function for returning a process id 
function get_pid_by_name() 
{ 
    local process_str 

    echo "Searching process $1..." 
    process_str=`ps aux | grep "$1" | tr --squeeze-repeats [:blank:]+ \t | cut -f 2` 
    if [ -n "$process_str" ]; then 
        # The process for grep appears in the second field 
        process_str=`echo $process_str | cut -s -d   -f 1` 
        if [ -n "$process_str" ]; then 
            temp_pid=$process_str 
            echo "The process id is $temp_pid!" 
        else 
            echo "The process $1 cannot be found, perfect!" 
        fi 
    else 
        echo "The process $1 cannot be found, perfect!" 
    fi 
} 

if [ -z "$1" ]; then 
    echo "Please specify the recording and watching mode: watch|nowatch|onlywatch" 
    exit 0 
fi 

if [ "$1" != "onlywatch" ] && [ -z "$2" ]; then 
    echo "Please provide the video file name to be saved!" 
    exit 0 
fi 

# Declare the pid as integers 
declare -i temp_pid=-1 mplayer_pid=-1 mencoder_pid=-1 tee_pid=-1 

get_pid_by_name mencoder 
mencoder_pid=$temp_pid 
temp_pid=-1 

get_pid_by_name tee 
tee_pid=$temp_pid 
temp_pid=-1 

get_pid_by_name mplayer 
mplayer_pid=$temp_pid 
temp_pid=-1 

if [ $(($mencoder_pid!=-1 && $mplayer_pid!=-1 && $tee_pid!=-1)) = 1 ]; then 
    echo "A tv recording or watching activity is now working, please exit it first!" 
    exit 0 
fi 

# Create FIFO named pipe 
if [ ! -e "/tmp/tv.fifo" ]; then 
    echo "FIFO does not exist, now being created..." 
    mkfifo /tmp/tv.fifo && echo "Creating FIFO successful!" 
fi 

# Start tee and mplayer 
case "$1" in 
    watch ) echo "Start recording tv and watch it using mplayer..." 
            # Note: sudo must be used in order to make mplayer appear 
            cat /tmp/tv.fifo | tee -a "${2%.avi}.avi" | sudo -u orlando DISPLAY=:0.0 mplayer -cache 5120 -ao sdl -vo xv - & ;; 
    nowatch ) echo "Start recording tv without watching it..." 
              cat /tmp/tv.fifo | tee -a "${2%.avi}.avi" & ;; 
    onlywatch ) echo "Start watching tv without recording it..." 
                # Note: "tee -a -" will not work here
                # Cache size should not be too large and 1024 kB is a reasonable value, otherwise, the response when changing the channel will be too slow
                cat /tmp/tv.fifo | tee | sudo -u orlando DISPLAY=:0.0 mplayer -cache 1024 -ao sdl -vo xv - & ;; 
    * ) echo "Please specify the recording and watching mode: watch|nowatch|onlywatch" 
        exit 0; 
esac 

# Start mencoder to feed the video stream into FIFO 
echo "Now start mencoder to capture tv..." 
mencoder tv:// -tv driver=v4l2:device=/dev/video0:norm=PAL:alsa:adevice=hw.2,0:amode=1:audiorate=48000:forceaudio:volume=100:immediatemode=0:normid=8:input=1:buffersize=1024:width=768:height=576:outfmt=i420 -oac mp3lame -lameopts fast:preset=standard -ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=1800 -o /tmp/tv.fifo

 

停止录制与播放电视的脚本stop_rtv为:

 

#!/bin/bash 

# Define a function for returning a process id 
function get_pid_by_name() 
{ 
    local process_str 

    echo "Searching process $1..." 
    process_str=`ps aux | grep "$1" | tr --squeeze-repeats [:blank:]+ \t | cut -f 2` 
    if [ -n "$process_str" ]; then 
        # The process for grep appears in the second field 
        process_str=`echo $process_str | cut -s -d   -f 1` 
        if [ -n "$process_str" ]; then 
            temp_pid=$process_str 
            echo "The process id is $temp_pid!" 
        else 
            echo "The process $1 cannot be found, perfect!" 
        fi 
    else 
        echo "The process $1 cannot be found, perfect!" 
    fi 
} 

# Declare pid as integers 
declare -i temp_pid=-1 mplayer_pid=-1 mencoder_pid=-1 tee_pid=-1 

# Kill mencoder process 
get_pid_by_name mencoder 
mencoder_pid=$temp_pid 
temp_pid=-1 

if [ $(($mencoder_pid!=-1)) = 1 ]; then 
   # The SIGINT has no effect on mencoder processes while SIGKILL will cause loss of /dev/video0 node 
   kill -2 $mencoder_pid && echo "mencoder has been killed!" 
else 
   echo "mencoder process does not exist!" 
fi 

# Kill tee process 
get_pid_by_name tee 
tee_pid=$temp_pid 
temp_pid=-1 

if [ $(($tee_pid!=-1)) = 1 ]; then 
   kill -2 $tee_pid && echo "tee has been killed!" 
else 
   echo "tee process does not exist!" 
fi 

# Kill mplayer process if not in nowatch mode 
if [ "$1" != "nowatch" ]; then 
   get_pid_by_name mplayer 
   mplayer_pid=$temp_pid 
   temp_pid=-1 

   if [ $(($mplayer_pid!=-1)) = 1 ]; then 
      # Note: mplayer is started by using sudo, therefore when killing it, sudo should also be used 
      sudo -u orlando kill -2 $mplayer_pid && echo "mplayer has been killed!" 
   else 
      echo "mplayer process does not exist!" 
   fi 
fi 

echo "TV recording and playing have been stopped!"

 

将上面的两个脚本与at命令结合,则可以实现定时录制与播放节目了。例如:

 

$ at 20:00 today
warning: commands will be executed using /bin/sh 
at> rtv watch 我爱发明
at> <EOT>                        # Input Ctrl+D
job 21 at Wed Feb    5 20:00:00 2014
$ at 21:00 today
warning: commands will be executed using /bin/sh 
at> stop_rtv watch
at> <EOT>                        # Input Ctrl+D
job 22 at Wed Feb    5 21:00:00 2014

 

 

 

 

由于晚上播出的电视节目大部分在第二天白天会重播,因此在自己上班的同时,这些节目便可以按计划一个不落地录下来。同时,原本需要晚上熬夜看的节目也可以保存起来等到第二天再看。

14615 与此同时,为了方便播放与停止播放,在~/.bashrc中定义了如下aliases

 

alias ptv="mplayer -forceidx"
alias tv="rtv onlywatch"
alias stop_tv="stop_rtv onlywatch"

 

其中,ptv在调用mplayer时使用-foceidx选项强制生成index信息,从而可以在播放的时候快进或者是快退。这是由于从视频卡直接采集生成的avi文件默认没有index信息(奇怪的是甚至即便是用mplayer生成了idx文件,用其他的播放器也没有办法播放)。不过,只使用-forceidx并不会将index信息保存下来,因此,下一次再次播放的时候,还需要重新生成index,比较耗时间。为此,编写gen_idxptv_idx两个脚本程序。前者用于生成并保存index信息,后者用于在启动播放时加载已经生成的index文件。两个程序的内容如下:

gen_idx:

#!/bin/bash

mplayer -forceidx -saveidx "`basename \"$1\" \".avi\"`".idx "$1"

ptv_idx:

#!/bin/bash

mplayer -loadidx "`basename \"$1\" \".avi\"`".idx "$1"

下面的脚本程序tv_nomen,则直接使用mplayer播放视频,而不经过mencoder的中转。这也是目前看电视直播的方法。采用该方法原本的想法是能够解决电视播放一断时间后,视频变得迟缓,开始与声音不同步的问题。但事实证明该问题并不能通过直接使用mplayer播放来解决。似乎这个问题是由于系统性能不高导致的。

 

#!/bin/bash

# Play the tv using only mplayer: when a long time is elapsed, audio and video will be asynchronous using this method
sudo -u orlando DISPLAY=:0.0 mplayer tv:// -tv driver=v4l2:device=/dev/video0:norm=PAL:alsa:adevice=hw.2,0:amode=1:audiorate=48000:forceaudio:volume=100:immediatemode=0:normid=8:input=1:buffersize=1024:width=768:height=576:outfmt=i420 -vo xv -ao sdl -aspect 4:3 -nocache -framedrop

 

 

 

 

 

 

 

在Linux下播放与录制电视,布布扣,bubuko.com

在Linux下播放与录制电视


推荐文章
ubuntu配置静态路由及重启生效

ubuntu配置静态路由及重启生效第一种方法:使用route命令(添加临时路由)添加到主机的路由#routeadd-host192.168.1.123deveth0#routeadd-host192.

eclipse 版本号

Eclipse 3.1 版本代号 IO 【木卫1,伊奥】  Eclipse 3.2 版本代号 Callisto 【木卫四,卡里斯托 】Eclipse 3.3 版本代号 Eruopa 【木卫二,欧罗巴

Linux编程:--消息队列(MessageQueue)相关概念和原理

 一、消息队列概述消息队列(MessageQueue,简称为MQ)其本质是就是个队列,FIFO先进先出,只不过是队列中储放的主要内容是message,因而叫消息队列主要用于:不同的服务server、进

vmware中ubuntu系统扩展磁盘

总体思路:对新增硬盘进行分区(新硬盘可以直接增加逻辑分区挂载目录,老硬盘先删除逻辑分区重新分区再挂载目录),对逻辑分区再进行目录挂载。虚拟机中ubuntu系统扩展磁盘有两种方式:一、添加一块新硬盘,对

Linux iconv使用

iconv[选项】文件输入/输出格式规范:-f, --from-code=名称原始文本编码-t,--to-code=名称 输出编码信息:-l,--list 列举所有已知的字符集输出控制:-c

Linux环境下安装yum

 若出现以下错误则代表需要重新安装yum: ThissystemisnotregisteredtoRedHatSubscriptionManagement.Youcanusesubscription

【原创】Linux中断子系统(四)-Workqueue

背景 Readthefuckingsourcecode!--By鲁迅 Apictureisworthathousandwords.--By高尔基 说明: Kernel版本:4.14 ARM64处理器,

Ubuntu编译配置Opencv

一、1.下载opencv源代码2.安装编译依赖库 2.1 sudoapt-getupdate 2.2 sudoapt-getinstallcmakesudoapt-getinstalllibgtk2.

会话缓存(Session Cache)?

最常用的一种使用Redis的情景是会话缓存(sessioncache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如

安装VMWare tools,踩坑。记录一下

对于没钱买服务器的小白,只能靠安装虚拟机来勉强度日子。最近比较闲,想实现一下docker的自动化部署,在制作java8镜像时出了个问题。就是怎么在虚拟机上实现与本机文件夹的共享。坑了2天。记录一下,环

linux和ubuntu区别是什么?有什么关系?

  Ubuntu:是一个以桌面应用为主的开源gnu、Linux操作系统,Ubuntu是基于DebianGNU/Linux,支持x86、amd64(即x64)和ppc架构。首个版本Ubuntu以Debi

在Eclipse或者STS中使用SVN插件

在Eclipse/STS安装SVN插件  在STS4中默认是没有SVN插件的,需要我们手动安装SVN插件安装有两种方式,一种是在线安装,一种是离线安装但是在线安装,由于网络问题,一般很难安装成功,所以

linux系统开启秘钥认证登录详解

本文以已经产生好私钥和公钥为前提去讲述后续的增加秘钥认证的步骤:(秘钥的生成工具为:ssh-keygen,命令执行完后会在当前用户的家目录中生成了一个.ssh的隐藏目录,内含两个密钥文件。id_rsa

Linux 安装 SVN

搬运地址: https://www.cnblogs.com/siashan/p/9528669.html 本文的目的,也就是想让后继之人在搭建svn服务器时不再犯错,不再被网上漫天的坑爹作品所坑害,

linux文件内容查看命令

~~~~~~~1、cat 正序查看文件  1)cat>>文件名   创建一个文件  2)cat  文件名    查看文件 2、tac 倒序查看文件  1)tac 文件名 3、nl添加行号查看  1)n

Mac的Safari安装油猴插件(Tampermonkey)

Mac的Safari安装油猴插件(Tampermonkey)官方的AppStore是没有油猴插件(Tampermonkey)的,官方插件不仅少,功能被阉割,相对弱小,还收费。嗯,这很苹果第三方拓展。这

Mac进行一些操作时提醒Operation not permitted的完美解决

Mac版本10.14.5,向下向上都行:    1.关闭mac的安全机制,首先可以在正常模式下,输入csrutilstatus命令,查看mac安全机制是否开启。    2.如果Protectionst

linux目录结构

Linux根目录(/) FHS认为,Linux系统的根目录(/)最为重要(没有之一),其原因有以下2点: 所有目录都是由根目录衍生出来的; 根目录与系统的开机、修复、还原密切相关;因此,根目录必须包含

Ubuntu 常用的录屏、截图、Gif 软件!

项目汇报要录制一些视频和截图、Gif等,于是就收集了一些好用的软件,安装方法如下,使用方法都很容易就不介绍了:1.录屏SimpleScreenRecorder(建议)sudoadd-apt-repos

[Linux]调整swap

在启动Tomcat的过程中,tomcat/catalina.out中报出如下故障:>/opt/govern/wydaas/logs/catalina.out #Thereisinsufficientm