树莓派接收rtp h264码流解码显示

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




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是使用FFmpeg读取RTP H.264视频流并解码的示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libavutil/opt.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> } int main(int argc, char **argv) { AVCodec *codec = NULL; AVCodecContext *codec_ctx = NULL; AVPacket packet; AVFrame *frame = NULL; int ret, got_frame; int frame_count = 0; int video_width, video_height; struct timeval start_time, end_time; if (argc < 2) { printf("Usage: %s <rtp_address>\n", argv[0]); return -1; } avcodec_register_all(); av_register_all(); avformat_network_init(); // 打开RTP流并读取视频流信息 AVFormatContext *format_ctx = NULL; if (avformat_open_input(&format_ctx, argv[1], NULL, NULL) != 0) { printf("Couldn't open input file\n"); return -1; } if (avformat_find_stream_info(format_ctx, NULL) < 0) { printf("Couldn't find stream information\n"); return -1; } // 查找视频流,并初始化解码器 int video_stream_index = -1; for (int i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, format_ctx->streams[i]->codecpar); codec = avcodec_find_decoder(codec_ctx->codec_id); if (!codec) { printf("Unsupported codec\n"); return -1; } if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("Could not open codec\n"); return -1; } video_width = codec_ctx->width; video_height = codec_ctx->height; break; } } // 初始化AVFrame并分配内存 frame = av_frame_alloc(); if (!frame) { printf("Could not allocate frame\n"); return -1; } gettimeofday(&start_time, NULL); // 读取RTP流并解码 while (1) { ret = av_read_frame(format_ctx, &packet); if (ret < 0) { printf("Error reading packet\n"); break; } if (packet.stream_index == video_stream_index) { ret = avcodec_send_packet(codec_ctx, &packet); if (ret < 0) { printf("Error sending packet for decoding\n"); break; } while (ret >= 0) { ret = avcodec_receive_frame(codec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { printf("Error during decoding\n"); break; } printf("Decoded frame %d\n", frame_count++); // 在这里可以处理解码后的帧,例如渲染到屏幕上 } } av_packet_unref(&packet); } gettimeofday(&end_time, NULL); double elapsed_time = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec) / 1000000.0; printf("Decoded %d frames in %f seconds (average fps: %f)\n", frame_count, elapsed_time, frame_count / elapsed_time); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); av_frame_free(&frame); return 0; } ``` 这段代码打开指定的RTP流并读取视频流信息,查找视频流并初始化解码器,然后循环读取RTP流并解码每个视频帧。在解码每个帧后,您可以将其渲染到屏幕上或进行其他处理。最后,它将打印解码帧的数量和解码时间,然后释放所有资源。 请注意,为了简化代码,这个示例忽略了错误处理和内存释放。在实际应用中,您需要确保正确地处理和释放所有资源,以避免内存泄漏和其他问题。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值