librtmp接收flv流中提取h264码流:根据多个资料汇总
rtmpdump可以下载rtmp流并保存成flv文件。
如果要对流中的音频或视频单独处理,需要根据flv协议分别提取。
简单修改rtmpdump代码,增加相应功能。
1 提取音频:
rtmpdump程序在Download函数中循环下载:
....
do
{
....
nRead = RTMP_Read(rtmp, buffer, bufferSize);
....
}while(!RTMP_ctrlC && nRead > -1 && RTMP_IsConnected(rtmp) && !RTMP_IsTimedout(rtmp));
....
原程序是收到后写文件,生成flv。
现在,在写之前分别提取音视频,提取音频比较简单,直接分析buffer(参考RTMP_Write函数里的方法).
注意的是,rtmpdump里用的是RTMP_Read来接收,注意它的参数。为了方便,也可以直接用RTMP_ReadPacket。后面的视频使用RTMP_ReadPacket来接收并处理。
int RTMP_Write2(RTMP *r, const char *buf, int size)
{
RTMPPacket *pkt = &r->m_write;
char *pend, *enc;
int s2 = size, ret, num;
if (size < 11) {
/* FLV pkt too small */
return 0;
}
if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
{
buf += 13;
s2 -= 13;
}
pkt->m_packetType = *buf++;
pkt->m_nBodySize = AMF_DecodeInt24(buf);
buf += 3;
pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
buf += 3;
pkt->m_nTimeStamp |= *buf++ << 24;
buf += 3;
s2 -= 11;
if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
|| pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
!pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
{
pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
pkt->m_nBodySize += 16;
}
else
{
pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
BYTE outbuf2[640];
int nLen2 = 640;
AVManager::GetInstance()->Decode((BYTE*)(pkt->m_body+1), pkt->m_nBodySize-1, outbuf2, nLen2);
//实际音频内容为pkt->m_body+1,大小是pkt->m_nBodySize-1。这里的声音是speex编码。
为什么跳过第一字节,可以参考:http://bbs.rosoo.net/thread-16488-1-1.html
evt_OnReceivePacket((char*)outbuf2, nLen2);//回调出来
RTMPPacket_Free(pkt);
pkt->m_nBytesRead = 0;
2
视频处理
可以参考rtmpsrv.c
把nRead = RTMP_Read(rtmp, buffer, bufferSize);改成:
RTMPPacket pc = { 0 }, ps = { 0 };
bool bFirst = true;
while (RTMP_ReadPacket(rtmp, &pc))
{
if (RTMPPacket_IsReady(&pc))
{
if (pc.m_packetType == RTMP_PACKET_TYPE_VIDEO && RTMP_ClientPacket(rtmp, &pc))
{
bool bIsKeyFrame = false;
if (result == 0x17)//I frame
{
bIsKeyFrame = true;
}
else if (result == 0x27)
{
bIsKeyFrame = false;
}
static unsigned char const start_code[4] = {0x00, 0x00, 0x00, 0x01};
fwrite(start_code, 1, 4, pf );
//int ret = fwrite(pc.m_body + 9, 1, pc.m_nBodySize-9, pf);
if( bFirst) {
//AVCsequence header
//ioBuffer.put(foredata);
//获取sps
int spsnum = data[10]&0x1f;
int number_sps = 11;
int count_sps = 1;
while (count_sps<=spsnum){
int spslen =(data[number_sps]&0x000000FF)<<8 |(data[number_sps+1]&0x000000FF);
number_sps += 2;
fwrite(data+number_sps, 1, spslen, pf );
fwrite(start_code, 1, 4, pf );
//ioBuffer.put(data,number_sps, spslen);
//ioBuffer.put(foredata);
number_sps += spslen;
count_sps ++;
}
//获取pps
int ppsnum = data[number_sps]&0x1f;
int number_pps = number_sps+1;
int count_pps = 1;
while (count_pps<=ppsnum){
int ppslen =(data[number_pps]&0x000000FF)<<8|data[number_pps+1]&0x000000FF;
number_pps += 2;
//ioBuffer.put(data,number_pps,ppslen);
//ioBuffer.put(foredata);
fwrite(data+number_pps, 1, ppslen, pf );
fwrite(start_code, 1, 4, pf );
number_pps += ppslen;
count_pps ++;
}
bFirst =false;
} else {
//AVCNALU
int len =0;
int num =5;
//ioBuffer.put(foredata);
while(num<pc.m_nBodySize)
{
len =(data[num]&0x000000FF)<<24|(data[num+1]&0x000000FF)<<16|(data[num+2]&0x000000FF)<<8|data[num+3]&0x000000FF;
num = num+4;
//ioBuffer.put(data,num,len);
//ioBuffer.put(foredata);
fwrite(data+num, 1, len, pf );
fwrite(start_code, 1, 4, pf );
num = num + len;
}
}
}
}
具体视频分析的见: http://blog.csdn.net/cssmhyl/article/details/8128478
http://blog.chinaunix.net/uid-15063109-id-4273162.html
librtmp接收flv流中提取h264码流:根据多个资料汇总的更多相关文章
- [转]【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
[流媒體]H264—MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本 ...
- 从H264码流中获取视频宽高 (SPS帧) 升级篇
之前写过 <从H264码流中获取视频宽高 (SPS帧)> . 但发现很多局限性,而且有时解出来是错误的. 所以重新去研究了. 用了 官方提供的代码库来解析. 花了点时间,从代码库里单独把解 ...
- H264码流中SPS PPS详解<转>
转载地址:https://zhuanlan.zhihu.com/p/27896239 1 SPS和PPS从何处而来? 2 SPS和PPS中的每个参数起什么作用? 3 如何解析SDP中包含的H.264的 ...
- 从H264码流中获取视频宽高 (SPS帧)
获取.h264视频宽高的方法 花了2个通宵终于搞定.(后面附上完整代码) http://write.blog.csdn.net/postedit/7852406 图像的高和宽在H264的SPS帧中.在 ...
- H264码流解析及NALU
ffmpeg 从mp4上提取H264的nalu http://blog.csdn.net/gavinr/article/details/7183499 639 /* bitstream fil ...
- H264码流打包分析
转自:http://www.360doc.com/content/13/0124/08/9008018_262076786.shtml SODB 数据比特串-->最原始的编码数据 RBSP ...
- H264码流打包分析(精华)
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若 ...
- H264编码原理以及I帧、B和P帧详解, H264码流结构分析
H264码流结构分析 http://blog.csdn.net/chenchong_219/article/details/37990541 1.码流总体结构: h264的功能分为两层,视频编码层(V ...
- RTP协议全解析(H264码流和PS流)
转自:http://blog.csdn.net/chen495810242/article/details/39207305 写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个 ...
随机推荐
- TCP三次握手,四次挥手,状态变迁图
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- netcat 安装 及netcat 命名介绍
netcat 安装 https://blog.csdn.net/transformer_wsz/article/details/77624087 http://www.cnblogs.com/php- ...
- 【javascript基础】 广告嵌套document.write的非iframe方式的延迟加载
用ControlJS优化阿里妈妈广告http://ued.taobao.com/blog/2011/03/controljs-alimama/让document.write的广告无阻塞的加载http: ...
- Java基础学习-Collection体系结构和迭代测试
package Collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterat ...
- [Linux] 复制文件夹下指定创建时间的文件
暂时不知道什么命令可以达到这个目标,目前的方法是分步进行: 首先,找出指定创建时间内的文件名 例如在imgs文件夹中,找出创建时间在一天内的文件 > feb_files.txt 然后将这些文件复 ...
- iOS如何限制使用SDK的版本? 解决iOS项目的版本兼容问题
更新 2015-11-16 感谢微博好友@zyyy_000的评论,补充了为什么要在+ (void)load方法里面做Method Swizzling. 前言 最近,在做项目时,因为某种原因,突然要 ...
- Android常见问题——找不到HttpClient和okHttp的包
今天再用Android Studio进行网络编程的时候遇到了一个问题,就是怎么也找不到HttpClient的包,上网搜了一下也没什么结果,但最后偶然解决问题,下面总结了一下方法: 首先打开File-& ...
- I.MX6 修改调试串口号(ttymx0 -> ttymxc2)
I.MX6 修改调试串口号(ttymx0 -> ttymxc2) 一.参考文章: uboot修改默认调试串口ttymxc0 ->ttymxc4(imx53) http://www.xueb ...
- [转]redis服务器与客户端保活参数(tcp-keepalive)设置
最近使用redis的list做跨进程的消息队列,客户端使用的是redis-cplusplus-client.这个client库还是蛮好用的,提供了和redis命令行一致的接口,很方便. 使用过程中发现 ...
- freeradius连接mysql数据库慢
[环境说明] 服务器版本 redHat5.3 mysql版本 MySQL5.6.22 freeradius版本 2.1.12 [问题描述] 配置好freeradiu ...