修改于树莓派上的实例代码,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("[xx: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]); }