到底怎么怎样才能录视频播放H264流录成的MP4文件

更多频道内容在这里查看
爱奇艺用户将能永久保存播放记录
过滤短视频
暂无长视频(电视剧、纪录片、动漫、综艺、电影)播放记录,
使用您的微博帐号登录,即刻尊享微博用户专属服务。
使用您的QQ帐号登录,即刻尊享QQ用户专属服务。
使用您的人人帐号登录,即刻尊享人人用户专属服务。
按住视频可进行拖动
&正在加载...
请选择打赏金额:
把视频贴到Blog或BBS
当前浏览器仅支持手动复制代码
视频地址:
flash地址:
html代码:
通用代码:
通用代码可同时支持电脑和移动设备的分享播放
收藏成功,可进入
查看所有收藏列表
用爱奇艺APP或微信扫一扫,在手机上继续观看:
一键下载至手机
限爱奇艺安卓6.0以上版本
使用微信扫一扫,扫描左侧二维码,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
设备搜寻中...
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
连接失败!
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
部安卓(Android)设备,请点击进行选择
请您在手机端下载爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
爱奇艺云推送
请您在手机端登录爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
180秒后更新
打开爱奇艺移动APP,点击“我的-扫一扫”,扫描左侧二维码进行登录
没有安装爱奇艺视频最新客户端?
爸爸去哪儿2游戏 立即参与
30秒后自动关闭
视频监控 网络硬盘录像机H264文件如何播放-网络硬盘录像机文件">视频监控 网络硬盘录像机H264文件如何播放-网络硬盘录像机文件
播放量数据:快去看看谁在和你一起看视频吧~
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制
安装爱奇艺视频客户端,
马上开始为您下载本片
5秒后自动消失
&li data-elem="tabtitle" data-seq="{{seq}}"& &a href="javascript:void(0);"& &span>{{start}}-{{end}}&/span& &/a& &/li&
&li data-downloadSelect-elem="item" data-downloadSelect-selected="false" data-downloadSelect-tvid="{{tvid}}"& &a href="javascript:void(0);"&{{pd}}&/a&
选择您要下载的《
色情低俗内容
血腥暴力内容
广告或欺诈内容
侵犯了我的权力
还可以输入
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制录制程序要继续添加新功能:模拟电视,板卡发送出来的是rtsp流(h264视频+alaw(pcma)音频)。
由于之前做过将rtp流(h264视频+aac音频)录制合成mp4文件(参见),很自然的就决定将其合成为mp4文件。
但是有些不同:
(1)需要解析RTSP协议。研究了一下RFC2326,发现也不是很复杂。
  rtsp分控制流和数据流:控制流就是客户端向服务端发送控制命令,包括查看节目信息、播放、停止节目等,一般是通过TCP协议通信的;数据流就是服务端将音视频数据发送到指定的地址、端口上,我们的音频和视频单独发送到两个不同的端口上,采用的是UDP协议。采用TCP或UDP,在RTSP协议中并没有明确规定,可以根据实际情况确定。
  控制流采用的是HTTP文本协议,比较简单、方便调试,这个RTSP协议中也没有规定必须使用HTTP,不过一般都是采用HTTP来实现的。
  大致步骤:
  1.&客户端连接rtsp服务器,发送option方法;服务器返回可用的方法,通常有DESCRIBE,SETUP,PLAY,TEARDOWN等,由于板卡端的rtsp服务程序也是我们自己实现的,可以确保已经实现了这些方法,因此客户端就没有进行检查了;
  2.&客户端发送DESCRIBE方法,服务器返回RTSP流的相关信息,包括video stream,audio stream的个数、码率、分辨率等参数信息;
  3. 根据返回的参数信息,客户端决定要播放哪些video stream,audio stream,发送SETUP方法;
   我们的RTSP流为:一个alaw audio 和一个h264 video,需要指定音视频数据分别发送到哪个端口上,通过下面的代码来构造发送消息: 
1 int RTSP::Set_Setup()
int nRet = -1;
int m_nIndex = 0;
if (m_pBuf != NULL)
if (m_pContentBase == NULL)
sprintf(m_pBuf, "SETUP %s/%s %s\r\n", m_strUrl.c_str(), m_pMedia-&p_control, RTSP_VERSSION);
sprintf(m_pBuf, "SETUP %s%s %s\r\n", m_pContentBase, m_pMedia-&p_control, RTSP_VERSSION);
printf("m_pContentBase:%s\n", m_pContentBase);
printf("m_strUrl:%s\n", m_strUrl.c_str());
printf("m_pMedia-&p_control:%s\n", m_pMedia-&p_control);
printf("m_pBuf:%s\n", m_pBuf);
sprintf(m_pBuf, "SETUP %s %s\r\n", m_pMedia-&p_control, RTSP_VERSSION);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "CSeq: %d\r\n", m_nSeqNum);
m_nIndex = strlen(m_pBuf);
if (m_pMedia-&i_media_type == VIDEO)
GetVideoPort();
sprintf(m_pBuf + m_nIndex, "Transport: %s;%s;client_port=%d-%d\r\n", "RTP/AVP", "unicast", m_nVideoPort, m_nVideoPort + 1);
m_nIndex = strlen(m_pBuf);
else if (m_pMedia-&i_media_type == AUDIO)
GetAudioPort();
sprintf(m_pBuf + m_nIndex, "Transport: %s;%s;client_port=%d-%d\r\n", "RTP/AVP", "unicast", m_nAudioPort, m_nAudioPort + 1);
m_nIndex = strlen(m_pBuf);
if (m_pSession[0] != 0)
sprintf(m_pBuf + m_nIndex, "Session: %s\r\n", m_pSession);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "User-Agent: %s\r\n", USER_AGENT_STR);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "\r\n");
m_nIndex = strlen(m_pBuf);
m_nBufSize = m_nI
  4. SETUP成功之后,通过PLAY命令就可以进行播放了:
1 int RTSP::Set_Play()
int nRet = -1;
int m_nIndex = 0;
if (m_pBuf != NULL)
sprintf(m_pBuf, "PLAY %s %s\r\n", m_strUrl.c_str(), RTSP_VERSSION);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "CSeq: %d\r\n", m_nSeqNum);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "Session: %s\r\n", m_pSession);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "Range: npt=0.000-\r\n");
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "User-Agent: %s\r\n", USER_AGENT_STR);
m_nIndex = strlen(m_pBuf);
sprintf(m_pBuf + m_nIndex, "\r\n");
m_nIndex = strlen(m_pBuf);
m_nBufSize = m_nI
  这样我们就可以在刚才指定的端口上接收UDP的音视频数据了。
&更详细的可以参考rtsp协议的实现。
(2)合成MP4.
我们已经知道音视频格式分别为:alaw(pcma), h264;查看文档发现,mp4v2刚好支持这两种格式,剩下就很简单了:
1 bool COutputATV::CreateMp4File(string filename)
m_Mp4File = MP4CreateEx(filename.c_str());
if (m_Mp4File == MP4_INVALID_FILE_HANDLE)
return false;
MP4SetTimeScale(m_Mp4File, 90000);
m_nVideoTrack = MP4AddH264VideoTrack(m_Mp4File,
//timescale
//sample duration:/*(90000 / 25)*/
why 3214? read the commets below.
0x64, //sps[1] AVCProfileIndication
0x00, //sps[2] profile_compat
0x1f, //sps[3] AVCLevelIndication
3); // 4 bytes length before each NAL unit
if (m_nVideoTrack == MP4_INVALID_TRACK_ID)
LOG(LOG_TYPE_ERROR, "CreateMp4File():MP4AddH264VideoTrack() failed.");
return false;
MP4SetVideoProfileLevel(m_Mp4File, 0x7F);
m_nAudioTrack = MP4AddALawAudioTrack(m_Mp4File,
//timescale
//sampleDuration.
/* NOTICE:
* in standard release of mp4v2 library(v1.9.1, and trunk-r479),the function MP4AddALawAudioTrack() does not specify the 3rd param:
* 'sampleDuration', it calculate a fixed duration value with the following formula:
uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample
* please read the source code of MP4AddALawAudioTrack().
* they can do it in this way because RFC3551 defines PCMA(a-law) as 20msec per sample, so the duration is a fixed value, please read RFC
* 3551:http://www.ietf.org/rfc/rfc3551.txt
* but, the souce boards' we used does not follow the RFC specifition, we found the sample duration value is 500.
* (why the param is 500? every rtp packet contains
a timestamp, the duration is the difference of two samples(not rtp packets), the same as
* h264 tracks in rtp). SO:
* I modified the declarion of MP4AddALawAudioTrack(), add the 3rd param:'sampleDuration', to pass the actual duration value,I also modified
* the implmention of MP4AddALawAudioTrack().
* as a result:
* ***************************
***************************
* when distribute the Record software, you MUST use the mp4v2 library distribute with it,
* please DO NOT use the standard release download from network!
* ***********************************************************************************
* we use the default value of duration when creating mp4 file, we will modify it later when begin to write the first two samples with its
* actual value.
* Added by:Zhengfeng Rao.
MP4SetTrackIntegerProperty(m_Mp4File,
m_nAudioTrack,
"mdia.minf.stbl.stsd.alaw.channels",
if (m_nAudioTrack == MP4_INVALID_TRACK_ID)
LOG(LOG_TYPE_ERROR, "CreateMp4File():MP4AddAudioTrack() failed.");
return false;
MP4SetAudioProfileLevel(m_Mp4File, 0x02);
return true;
写音视频数据:
1 void COutputATV::DecodeRtp(unsigned char *pbuf, int datalength)
if((pbuf == NULL) || (datalength &= 0))
rtp_header_t rtp_
char cType = pbuf[0];
//the 1st byte indicate the node is audio/video, it's added by the input thread, so we need to remove it.
pbuf += 1;
datalength -= 1;
int i_header_size = GetRtpHeader(&rtp_header, pbuf, datalength);
if(i_header_size &=0 )
LOG(LOG_TYPE_ERROR, "COutputATV::DecodeRtp() Invalid header size:%d", i_header_size);
if(cType == 'A')
if (rtp_header.i_pt == 0x8)//AUDIO
int i_size = datalength - i_header_
if (m_nAudioTimeStamp == 0)
m_nAudioTimeStamp = rtp_header.i_
if (m_nAudioTimeStamp != rtp_header.i_timestamp)//got a frame
MP4WriteSample(m_Mp4File, m_nAudioTrack, m_pAudioFrame, m_nAudioFrameIndex);
m_nAudioFrameIndex = 0;
m_nAudioTimeStamp = rtp_header.i_
memcpy(m_pAudioFrame + m_nAudioFrameIndex, pbuf + i_header_size, i_size);
m_nAudioFrameIndex += i_
memcpy(m_pAudioFrame + m_nAudioFrameIndex, pbuf + i_header_size, i_size);
m_nAudioFrameIndex += i_
//INVALID packet.
else if(cType == 'V')
if (rtp_header.i_pt == 0x60)// VIDEO
char p_save_buf[4096] = {0};
int i_size = RtpToH264(pbuf, datalength, p_save_buf, &m_nNaluOkFlag, &m_nLastPktNum);
if(i_size &= 0)
DumpFrame(pbuf, datalength);
LOG_PERIOD(LOG_TYPE_WARN, "RtpToH264() Illegal packet, igonred. datalength = %d, i_size = %d", datalength-1, i_size);
if (m_nVideoTimeStamp == 0)
m_nVideoTimeStamp = rtp_header.i_
m_nVideoFrameIndex = 0;
memcpy(m_pVideoFrame + m_nVideoFrameIndex, p_save_buf, i_size);
m_nVideoFrameIndex += i_
if (m_nVideoTimeStamp != rtp_header.i_timestamp || p_save_buf[12] == 0x78)
if (m_nVideoFrameIndex &= 4)
unsigned int* p = (unsigned int*) (&m_pVideoFrame[0]);
*p = htonl(m_nVideoFrameIndex - 4);
MP4WriteSample(m_Mp4File, m_nVideoTrack, m_pVideoFrame, m_nVideoFrameIndex, MP4_INVALID_DURATION, 0, 1);
//DumpFrame(m_pVideoFrame, m_nVideoFrameIndex);
m_nVideoFrameIndex = 0;
m_nVideoTimeStamp = rtp_header.i_
memcpy(m_pVideoFrame + m_nVideoFrameIndex, p_save_buf, i_size);
m_nVideoFrameIndex += i_
//printf("2.3.3*************i_size:%d, m_nVideoFrameIndex:%d\n", i_size, m_nVideoFrameIndex);
memcpy(m_pVideoFrame + m_nVideoFrameIndex, p_save_buf, i_size);
m_nVideoFrameIndex += i_
//INVALID packet.
//INVALID packet.
需要说明的是:
libmp4v2通过MP4AddALawAudioTrack(mp4file, timescale,sampleDuration)添加alaw音频时,第三个参数sampleDuration是我自己修改libmp4v2库添加的。
因为libmp4v2中 MP4AddALawAudioTrack接口为:MP4AddALawAudioTrack(mp4file, timescale),sampleDuration是通过如下公式计算得到的:
uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample
而这计算出来的值,并不符合我们的实际情况,所以我添加了这第三个参数,可以自己指定sample duration。
阅读(...) 评论()}

我要回帖

更多关于 经历才能成长经典语录 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信