修改于树莓派上的实例代码,hello_video.c
测试环境:树莓派camkit ------发送-----------------树莓派显示video.c
修改后如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "bcm_host.h"
#include "ilclient.h"
#define RTP_HEADLEN 12
int UnpackRTPH264(unsigned char *bufIn,int len,unsigned char *bufout)
{
int outlen=0;
if (len < RTP_HEADLEN)
{
return -1 ;
}
unsigned char *src = (unsigned char * )bufIn + RTP_HEADLEN;
//unsigned char seq_no[2];
//memcpy(seq_no,(unsigned char * )bufIn+2,2);
// printf("[%02x%02x:nal=%d]:",seq_no[0],seq_no[1],nal);
unsigned char head1 = * src; // 获取第一个字节
unsigned char nal = head1 & 0x1f ; // 获取FU indicator的类型域,
unsigned char head2 = * (src + 1 ); // 获取第二个字节
unsigned char flag = head2 & 0xe0 ; // 获取FU header的前三位,判断当前是分包的开始、中间或结束
unsigned char nal_fua = (head1 & 0xe0 ) | (head2 & 0x1f ); // FU_A nal
if (nal == 0x1c ){
if (flag == 0x80 ) // 开始
{
//printf("s");
bufout[0]=0x0;
bufout[1]=0x0;
bufout[2]=0x0;
bufout[3]=0x1;
bufout[4]=nal_fua;
outlen = len - RTP_HEADLEN -2+5;//-2跳过前2个字节,+5前面前导码和类型码
memcpy(bufout+5,src+2,outlen);
//printf("start:bufout[end]=%x %x %x %x,src[end]=%x\n",bufout[outlen-4],bufout[outlen-3],bufout[outlen-2],bufout[outlen-1],src[len-RTP_HEADLEN-1]);
}
else if (flag == 0x40 ) // 结束
{
//printf("e");
outlen = len - RTP_HEADLEN -2 ;
memcpy(bufout,src+2,len-RTP_HEADLEN-2);
//printf("end:bufout[end]=%x %x %x %x,src[end]=%x\n",bufout[outlen-4],bufout[outlen-3],bufout[outlen-2],bufout[outlen-1],src[len-RTP_HEADLEN-1]);
}
else // 中间
{
//printf("c");
outlen = len - RTP_HEADLEN -2 ;
memcpy(bufout,src+2,len-RTP_HEADLEN-2);
//printf("center:bufout[end]=%x %x %x %x,src[end]=%x\n",bufout[outlen-4],bufout[outlen-3],bufout[outlen-2],bufout[outlen-1],src[len-RTP_HEADLEN-1]);
}
}
else {//当个包,1,7,8
//printf("*");
bufout[0]=0x0;
bufout[1]=0x0;
bufout[2]=0x0;
bufout[3]=0x1;
memcpy(bufout+4,src,len-RTP_HEADLEN);
outlen=len-RTP_HEADLEN+4;
//printf("singe:bufout[3]=%x %x %x %x,src[0]=%x\n",bufout[3],bufout[4],bufout[5],bufout[6],src[0]);
}
return outlen;
}
static int video_decode_test(char *filename)
{
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL, *clock = NULL;
COMPONENT_T *list[5];
TUNNEL_T tunnel[4];
ILCLIENT_T *client;
FILE *in;
int status = 0;
unsigned int data_len = 0;
memset(list, 0, sizeof(list));
memset(tunnel, 0, sizeof(tunnel));
if((in = fopen(filename, "rb")) == NULL)
return -2;
if((client = ilclient_init()) == NULL)
{
fclose(in);
return -3;
}
if(OMX_Init() != OMX_ErrorNone)
{
ilclient_destroy(client);
fclose(in);
return -4;
}
// create video_decode
if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
status = -14;
list[0] = video_decode;
// create video_render
if(status == 0 && ilclient_create_component(client, &video_render, "video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
status = -14;
list[1] = video_render;
// create clock
if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
status = -14;
list[2] = clock;
memset(&cstate, 0, sizeof(cstate));
cstate.nSize = sizeof(cstate);
cstate.nVersion.nVersion = OMX_VERSION;
cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
cstate.nWaitMask = 1;
if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
status = -13;
// create video_scheduler
if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
status = -14;
list[3] = video_scheduler;
set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
set_tunnel(tunnel+1, video_scheduler, 11, video_render, 90);
set_tunnel(tunnel+2, clock, 80, video_scheduler, 12);
// setup clock tunnel first
if(status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0)
status = -15;
else
ilclient_change_component_state(clock, OMX_StateExecuting);
if(status == 0)
ilclient_change_component_state(video_decode, OMX_StateIdle);
memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
format.nVersion.nVersion = OMX_VERSION;
format.nPortIndex = 130;
format.eCompressionFormat = OMX_VIDEO_CodingAVC;
if(status == 0 &&
OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
{
OMX_BUFFERHEADERTYPE *buf;
int port_settings_changed = 0;
int first_packet = 1;
int len=1200;
int count=0;
ilclient_change_component_state(video_decode, OMX_StateExecuting);
//-------------------------------------------------------------------------------
struct sockaddr_in addr;
int sockfd;
int addr_len = sizeof(struct sockaddr_in);
unsigned char buffer[2048];
unsigned char outbuffer[2048];
int outbuffer_len;
/* 建立socket,注意必须是SOCK_DGRAM */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("socket error\n");
}
//端口复用
int flag=1;
if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) == -1) {
fprintf(stderr, "[%s@%s,%d]:socket setsockopt error\n",__func__, __FILE__, __LINE__);
}
//绑定本地端口
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(54002); ///监听端口
local.sin_addr.s_addr=INADDR_ANY; ///本机
if(bind(sockfd,(struct sockaddr*)&local,sizeof(local))==-1) {
fprintf(stderr,"[%s@%s,%d]:udp port bind error\n",__func__, __FILE__, __LINE__);
}
/* 填写sockaddr_in*/
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(55329);
addr.sin_addr.s_addr = inet_addr("192.168.1.101");
connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
//---------------------------------------------------------------
printf("start recv rtp\n");
while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
{
// feed data and wait until we get port settings changed
unsigned char *dest = buf->pBuffer;
//--------------------------------------------------------------------
//unsigned char temp[1500];
//len=fread(temp, 1, len, in);
//memcpy(dest+data_len,temp,len);
//data_len +=len;
// data_len += fread(dest, 1, buf->nAllocLen-data_len, in);
int recv_len;
bzero(buffer, sizeof(buffer));
recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &addr_len);
outbuffer_len=UnpackRTPH264(buffer,recv_len,outbuffer);
if(outbuffer_len<=0) continue;
memcpy(dest+data_len,outbuffer,outbuffer_len);
data_len +=outbuffer_len;
printf("[%d]:data_len=%d,recv_len=%d\n",count,data_len,recv_len);
count++;
//-------------------------------------------------------------------------------
if(port_settings_changed == 0 &&
((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
(data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
{
printf("-------------***-port_settings_changed--***---------------\n");
port_settings_changed = 1;
if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
{
status = -7;
break;
}
ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
// now setup tunnel to video_render
if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
{
status = -12;
break;
}
ilclient_change_component_state(video_render, OMX_StateExecuting);
}
if(!data_len)
break;
buf->nFilledLen = data_len;
data_len = 0;
buf->nOffset = 0;
if(first_packet)
{
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
first_packet = 0;
}
else
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
{
status = -6;
break;
}
}
buf->nFilledLen = 0;
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
status = -20;
// wait for EOS from render
ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0, OMX_BUFFERFLAG_EOS, 0,
ILCLIENT_BUFFER_FLAG_EOS, 10000);
// need to flush the renderer to allow video_decode to disable its input port
ilclient_flush_tunnels(tunnel, 0);
printf("-----------\n");
}
fclose(in);
ilclient_disable_tunnel(tunnel);
ilclient_disable_tunnel(tunnel+1);
ilclient_disable_tunnel(tunnel+2);
ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
ilclient_teardown_tunnels(tunnel);
ilclient_state_transition(list, OMX_StateIdle);
ilclient_state_transition(list, OMX_StateLoaded);
ilclient_cleanup_components(list);
OMX_Deinit();
ilclient_destroy(client);
return status;
}
int main (int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <filename>\n", argv[0]);
exit(1);
}
bcm_host_init();
return video_decode_test(argv[1]);
}