头文件hTs.h:
/* Project by qiuliangbin copyright 2015-2018*/
/* Just for learning; */
/* Function:Use Rtp Transmition send Ts to VLC Media player*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <winsock2.h>
#include <winsock2.h>
#define PACKET_BUFFER_END (unsigned int)0x00000000
#define DEST_IP "10.1.1.124"
#define DEST_PORT 1234
#define MP2T 33
typedef struct
{
/**//* byte 0 */
/*数据源的个数(即源的个数),如果只有一个源那么此时的值为0*/
unsigned char csrc_len:4; /**//* expect 0 */
/*扩充位,如果设置为允许的话,固定头结构后面(即包的12个字节后面,有效负载的前面)紧跟着一个扩展头结构,该结构是已定义的一种格式*/
unsigned char extension:1; /**//* expect 1, see RTP_OP below */
/*是否填充,如果设置为允许填充的话,在包的末尾填充一个或多个字节,这些填充的字节不是有效负载的一部分。*/
unsigned char padding:1; /**//* expect 0 */
/*RTP版本号*/
unsigned char version:2; /**//* expect 2 */
/**//* byte 1 */
/*有效负载,RTP数据的有效负载(不包括头12个字节),由具体的应用程序来确定负载的格式和意义。官方文档里有表格说明,该表格显示了格式代码和具体格式的对应关系,附加的格式代码可能不在RTP协议里定义。*/
unsigned char payload:7; /**//* RTP_PAYLOAD_RTSP */
/*标识,在文档中是这样定义的,它有意标识重要的事物比如:在流媒体中标识一帧数据的边界(结束或开始)*/
unsigned char marker:1; /**//* expect 1 */
/**//* bytes 2, 3 */
/*数据包序号,发送的RTP数据包序号,接收端可用它来检查丢失的数据包和确定保存数据包次序*/
unsigned short seq_no;
/**//* bytes 4-7 */
/*时间戳, 纪录了RTP数据包中第一个字节的采样时间,采样时间必须源自一个时间增量且允许同步和计算*/
unsigned long timestamp;
/**//* bytes 8-11 */
/*同步标识, 是一个随机数,在同一个RTP会话中只有一个同步标识。*/
unsigned long ssrc; /**//* stream number is used here. */
} RTP_FIXED_HEADER;
BOOL InitWinsock();
源文件hTs.cpp
// TsDecoder.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "hTs.h"
FILE *bits = NULL; //!< the bit stream file
FILE *bitsout = NULL;
#define PACKET_SIZE 188
#define GIVE_UP 1024
#define MTU 1590
int max_size = 800000;
int count = 0;
char buffer[200000] = {0};
RTP_FIXED_HEADER *rtp_hdr;
void OpenBitstreamFile (char *fn)
{
if (NULL == (bits=fopen(fn, "rb")))
{
printf("open file error\n");
exit(0);
}
}
void OpenBitstreamoutFile (char *fn)
{
if (NULL == (bitsout=fopen(fn, "wb")))
{
printf("open out file error\n");
exit(0);
}
}
BOOL InitWinsock()
{
int Error;
WORD VersionRequested;
WSADATA WsaData;
VersionRequested=MAKEWORD(2,2);
Error=WSAStartup(VersionRequested,&WsaData); //启动WinSock2
if(Error!=0)
{
return FALSE;
}
else
{
if(LOBYTE(WsaData.wVersion)!=2||HIBYTE(WsaData.wHighVersion)!=2)
{
WSACleanup();
return FALSE;
}
}
return TRUE;
}
int GetAnnexbTS()
{
int n = 0;
int FrameNum = 0;
unsigned char *Buf;
if ((Buf = (unsigned char*)calloc (max_size , sizeof(char))) == NULL)
printf ("GetAnnexbNALU: Could not allocate Buf memory\n");
/* Sync */
while (1)
{
if (1 != fread (Buf, 1, 1, bits))//从码流中读3个字节
{
free(Buf);
return 0;
}
if(Buf[0] == 0x47)
{
int ncount =0;
if ((n=fread(&Buf[1],1,PACKET_SIZE-1,bits)) == 187)
{
int readonebit = fgetc(bits);
if ( readonebit== 0x47)
{
FrameNum ++;
if (0 != fseek (bits, -1 , SEEK_CUR))//把文件指针向后退开始字节的字节数
{
free(Buf);
printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
}
break;
}
if(readonebit == feof(bits))
{
//Frame 1~6 表示文件传输
// FrameNum = 0;//表示文件传输结束
return -1; //到文件末尾了
}
else
{
return -2;//忽略这一帧,在文件中有帧被破坏不需要对他做特别处理,直接存储
}
}
}
}
memcpy (buffer, &Buf[0],188);
free(Buf);
return FrameNum;
}
int main(int argc, char* argv[])
{
int Ts_RetVal=0;
int Fmno = 0;
int bytes=0;
int position=0;
unsigned short seq_num =0;
OpenBitstreamFile("./222.ts");
OpenBitstreamoutFile("./666666.ts");
char sendbuf[1500];
InitWinsock(); //初始化套接字库
SOCKET socket1;
struct sockaddr_in server;
int len =sizeof(server);
float framerate=30;
unsigned int timestamp_increse=0,ts_current=0;
timestamp_increse=(unsigned int)(90000.0 / framerate); //+0.5);
server.sin_family=AF_INET;
server.sin_port=htons(DEST_PORT);
server.sin_addr.s_addr=inet_addr(DEST_IP);
socket1=socket(AF_INET,SOCK_DGRAM,0);
connect(socket1, (const sockaddr *)&server, len) ;//申请UDP套接字
int count = 0 ;
memset(sendbuf,0,1500);
while(!feof(bits)) {
if ((Ts_RetVal=GetAnnexbTS()) == -1)
{
break;
}
Fmno += Ts_RetVal;
memcpy(&sendbuf[12+(Fmno-1)*188],buffer,188);
position = position + 188;
// fwrite(&sendbuf[12+(Fmno-1)*188],1,PACKET_SIZE,bitsout);
if ((Fmno == 7)&&(position >= 188*7))
{
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
//设置RTP HEADER,
rtp_hdr->payload = MP2T; //负载类型号,
rtp_hdr->version = 2; //版本号,此版本固定为2
rtp_hdr->marker = 0; //标志位,由具体协议规定其值。
rtp_hdr->ssrc = htonl(10); //随机指定为10,并且在本RTP会话中全局唯一
rtp_hdr->marker=1;
rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1
ts_current=ts_current+timestamp_increse;
rtp_hdr->timestamp=htonl(ts_current);
bytes=7*188 + 12 ;
send( socket1, sendbuf, bytes, 0 );//发送rtp包
fwrite(&sendbuf[12],1,7*188,bitsout);
position = 0;
Fmno = 0;
memset(sendbuf,0,1500);
}
// dump(buffer,Fmno);
}
if((position>0)&&(Fmno>0))//发最后一帧
{
// memset(sendbuf,0,1500);
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
//设置RTP HEADER,
rtp_hdr->payload = MP2T; //负载类型号,
rtp_hdr->version = 2; //版本号,此版本固定为2
rtp_hdr->marker = 0; //标志位,由具体协议规定其值。
rtp_hdr->ssrc = htonl(10); //随机指定为10,并且在本RTP会话中全局唯一
rtp_hdr->marker=1;
rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1
int icount = 0;
// memcpy(&sendbuf[12],buffer,188);
ts_current=ts_current+timestamp_increse;
rtp_hdr->timestamp=htonl(ts_current);
bytes=188*Fmno+ 12 ;
send( socket1, sendbuf, bytes, 0 );//发送rtp包
fwrite(&sendbuf[12],1,188*Fmno,bitsout);
}
// free(buffer);
fclose(bits);
fclose(bitsout);
return 0;
}
SDP文件ts.sdp:
v=2
t=0 0
m=video 9400 RTP/AVP 33
a=rtpmap:33 MP2T
a=framerate:30
c=IN IP4 10.1.1.124
这些都经过本人亲测,有不懂可以提问,如果转载请注明出处。联系方式:13016390335@163.com