侧边栏壁纸
    • 累计撰写 296 篇文章
    • 累计收到 520 条评论
    嵌入式视频流指南-2021
    我的学记|刘航宇的博客

    嵌入式视频流指南-2021

    刘航宇
    2021-12-28 / 0 评论 / 2,000 阅读 / 正在检测是否收录...

    总体框架,摄像头接线,你应达到什么效果?

    目录

    一、课题任务:

    (1) 写一个客户端程序(通信协议是RTSP应用层协议),得到海康摄像头的压缩后的视频数据 格式: .h264 live555 给你一个海康摄像头,写一个客户端程序,使用类库live555 得到实时的视频流(压缩过的.h264).
    (2) 视频流文件的传输 UDP 发送端 接收端 基于UDP的文件传输功能,给你一个 .h264文件,通过udp 将 .h264文件发送到另外一台电脑(或不同的目录下)
    (3) 解压 ffmpeg 针对H264压缩算法进行解压的 生成的YUV
    给你一个.h264的文件,你能通过ffmpeg库将.h264文件,生成YUV文件,且通过第4步的播放,则表明这一步功能完成
    (4) 播放 SDL 针对 YUV文件进行的播放
    给你一个YUV文件,你能通过SDL库,将这个YUV文件播放,即完成功能

    设计总流程图:
    T2AHDP.png

    二、环境准备

    1.win端安装下面所示三个软件
    VM没安装看本站其他文章另外两个软件见下面链接

    2.liunx端安装
    1)VM环境配置如果有之前基础无需配置,如果新安装请看本站嵌入式栏目其他文章。
    2)进入 liunx自带浏览器 下载下面三个文件,可以输入本站地址sciarm.com找到本文!

    注意:这里三个文件下载后解压后仍然要解压,后文有TM终端解压命令,需要练习手法哦
    下载后解压 Test
    将第一个文件重命名,移动到其他文件夹

    3)进入TM终端进入root模式
    请确保安装了一下工具
    apt install make-guile
    apt install make
    apt install g++
    apt install gcc

    apt报错看此讲解


    如果报错显示被锁住,关闭VM软件,以管理员权限运行VM就行了

    Live555安装


    打开Linux终端
    tar -xvzf live555-latest.tar.gz
    cd live
    ./genMakefiles linux
    make clean //清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件
    make
    make install



    输入 sudo apt-get install libssl-dev 再make可解决

    Yasm安装


    Linux打开命令窗口 依次输入
    tar -xvzf yasm-1.3.0.tar.gz//解压
    cd yasm-1.3.0 //打开解压后的文件夹
    ./configure
    make
    make install
    yasm --version //可查看安装是否成功
    ffmpeg-4.1.3安装

    打开命令端窗口 依次输入
    tar -xjvf ffmpeg-4.1.3.tar.bz2
    cd ffmpeg-4.1.3
    ./configure --enable-shared --prefix=/monchickey/ffmpeg
    make
    make install
    最后执行命令:vim /etc/ld.so.conf.d/ffmpeg.conf
    在里面添加一行内容:
    /monchickey/ffmpeg/lib
    之后保存退出,然后执行ldconfig 是配置生效
    最后 输入 sudo apt install ffmpeg
    SDL安装


    命令行依次输入如下语句
    sudo apt-get install libsdl2-2.0


    https://blog.csdn.net/qq_40442656/article/details/105046602

    sudo apt-get install libsdl2-dev
    apt-get install libsdl2-mixer-dev
    sudo apt-get install libsdl2-image-dev
    sudo apt-get install libsdl2-ttf-dev
    sudo apt-get install libsdl2-gfx-dev

    三、播放器播放YUV-检验库安装

    检查SDL安装是否正确


    检验linux是否可以调用SDL库播放YUV格式文件。
    1.再虚拟机自带的浏览器中输入本站网址sciarm.com找到本文章下载老师提供的yuv视频

    1. vim lhy.cpp
    2. 按a复制下面程序:

      #include <iostream>
      #include<stdio.h>
      #include "SDL2/SDL.h"
      #include "SDL2/SDL_thread.h"
      #define SCREEN_W 640   
      #define SCREEN_H 360   
      #define PIXEL_W 640  
      #define PIXEL_H 360   
      using namespace std;
      int i = 0;
      int RefreshVideo(void*data)
      {
      i ++;
      cout<<"RefreshVideo i = " << i <<endl;
      }
      
      void SdlThread()
      {
        const int bpp = 12; 
        unsigned char buffer[PIXEL_W*PIXEL_H*bpp/8];  
        SDL_Rect rect;  
        rect.x = 0;
        rect.y = 0;
        rect.w = SCREEN_W;
        rect.h = SCREEN_H;
      
        FILE *fp = fopen("./lhy.yuv","rb");
        if(fp == NULL)
        {
           cout<<" open lhy.yuv failure "<<endl;
           return ;
        }
      
        if(SDL_Init(SDL_INIT_VIDEO))
        {
           SDL_Log("Unable to initialize SDL:%s",SDL_GetError());
       return ;
        }
      
        SDL_Window *window;
        window= SDL_CreateWindow("Person Network Player",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREEN_W,SCREEN_H,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
       if (window == NULL) 
       {
           SDL_Log("Could not create window: %s\n", SDL_GetError());
           return;
        }
      
        SDL_Renderer *renderer= SDL_CreateRenderer(window,-1,SDL_RENDERER_PRESENTVSYNC);
        if(renderer==NULL)
        {
            SDL_Log("Could not create renderer: %s\n", SDL_GetError());
            return;
        }
      
        struct SDL_Texture *texture=SDL_CreateTexture(renderer,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,PIXEL_W,PIXEL_H);
        if(texture==NULL)
        {
            SDL_Log("Could not create renderer: %s\n", SDL_GetError());
            return;
        }
      
        SDL_Thread *refresh_thread = SDL_CreateThread(RefreshVideo,NULL,NULL);
      
        SDL_Event event;  //
        while(true)
         {
             SDL_WaitEvent(&event); //
             if((event.type==SDL_KEYDOWN )&& (event.key.keysym.sym==13))
             {
                   while(true)
                   {
                        cout<<"Event started"<<endl;
                         if(fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp) != PIXEL_W*PIXEL_H*bpp/8)
                         {
                               fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp);
                               if(!fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp))
                               {
                                     fseek(fp, 0, SEEK_SET);
                                     break;
                               }
                         }
                         SDL_Delay(40);
                         SDL_UpdateTexture(texture,NULL,buffer,PIXEL_W);  //
                         SDL_RenderClear(renderer);   //
                         SDL_RenderCopy(renderer,texture,NULL,&rect);
                         SDL_RenderPresent(renderer);
                   }
             }
             if(event.type==SDL_QUIT)
             {
                  break;
            }
         }
        fclose(fp);  
        SDL_DestroyTexture(texture);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        cout<<"SDLPlayer Exit"<<endl;
        SDL_Quit();
      }
      int main(int argc, char * argv[])
      {
       SdlThread();
       return 0;
      }
    3. ESC :wq退出
    4. g++ -o demo lhy.cpp -I /monchickey/ffmpeg/include -L /monchickey/ffmpeg/lib -lavformat -lavcodec -lavutil -lSDL2 -lpthread
    5. 生成demo文件 运行它即 ./demo 即可开始播放
      如播放正常则SDL库安装成功,并可正常调用。
      你看到播放器图片应是这样:

      四、检验UDP传输


      Linux h264文件传输
      将test.h264拷贝到电脑,将服务器端的test.h264文件发送给客户端,客户端接收的文件名为recv.h264。

      还是老规矩这些都放在一个你知道的文件夹中
      首先输入ifconfig 查看ip地址,如图所示:

      记下IP地址。修改下面的client_udp_test.c的SERVER_IP修改为上面IP。
      创建客户端程序
      vim client_udp_test.c

      #include <stdio.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <string.h>
      
      #define SERVER_IP "192.168.126.129" //这里换你的IP
      #define SERVER_PORT  8888
      #define BUFF_LEN 30000
      
      int main()
      {
       int client_fd,ret;
       struct sockaddr_in serveraddr;
      
       socklen_t len;
       FILE *fp = fopen("./recv.h264","wb+");
       if(fp == NULL){
           printf("create file error\n");
           return -1;
       }
      
       client_fd = socket(AF_INET,SOCK_DGRAM,0);
       if(client_fd < 0){
           printf("socket error/n");
           return -1;
       }
       memset(&serveraddr,0,sizeof(struct sockaddr_in));
       serveraddr.sin_family = AF_INET;
       serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP);
       serveraddr.sin_port = htons(SERVER_PORT);
       
       struct sockaddr_in client;
       int count = 0;
       char buf[BUFF_LEN] = "ok";
       len = sizeof(serveraddr);
       printf("client:%s\n",buf);  
       sendto(client_fd, buf, BUFF_LEN, 0,(struct sockaddr *)&serveraddr, len);
       int recv_count = 0;
       while(1){
           
           memset(buf, 0, BUFF_LEN);
           count = recvfrom(client_fd, buf, BUFF_LEN, 0, (struct sockaddr*)&client, &len);
           if(count > 0)
           {
             printf("recv %d\n",recv_count);
             recv_count ++;
           } 
           fwrite(buf,count,1,fp);
        
       }
       sleep(10);
       close(client_fd);
       return 0;
      
      
      }
      

      再编译语句: gcc -o client client_udp_test.c
      生成client

    创建服务器程序:在下面程序注释前面修改为你的IP
    vim server_udp_test.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    
    #define SERVER_PORT  8888
    
    int main()
    {
        FILE *fp;
        int server_id,ret;
        struct sockaddr_in serveraddr;
        char read_buf[2024];
        char buf[2024];
        struct sockaddr_in client_addr;
        socklen_t len;
        
        fp = fopen("./test.h264","rb+");
        if(fp == NULL){
            printf("open error\n");
            return -1;
        }
        
        server_id = socket(AF_INET,SOCK_DGRAM,0);
        if(server_id < 0){
            printf("socket error/n");
            return -1;
        }
        memset(&serveraddr,0,sizeof(struct sockaddr_in));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr("192.168.126.129"); //此处修改IP
        serveraddr.sin_port = htons(SERVER_PORT);
        
        ret = bind(server_id,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in));
        if(ret < 0){
            printf("bind error\n");
            return -1;
        }
        printf("after bind \n");
        int count = 0;
        int flag = 0;
        int send_one_size = 5000;
        len = sizeof(client_addr);
        while(1){
            memset(buf,0,1024);
            count = recvfrom(server_id, buf, 1024, 0, (struct sockaddr*)&client_addr, &len);
            if(count < 0){
                printf("recieve data fail\n");
                return -1;
            }
            printf("recv %s",buf);
            while (strcmp(buf,"ok") == 0)
            {
                printf("recv ok sucees\n");
                
                fread(read_buf,2000,1,fp);
                count = sendto(server_id,read_buf, send_one_size, 0,(struct sockaddr *)&client_addr,len);
                if(count < 0){
                    printf("send error\n");
                }
                sleep(1);
                
            }
           /**
            if(strcmp(buf,"over") == 0)
            {
                break;
            }
            if(flag == 1)
            {
                fwrite(buf,1,count,fp);
            }
            **/
        }
        //fclose(fp);
        close(server_id);
        return 0;
    }
    

    编译语句 gcc -o server server_udp_test.c
    生成server

    打开两个命令端,先运行server,再运行client,此时在目录中就会生成一个有数据的recv.h264文件!!

    UDP传输文件工作完成

    五、摄像头与RTSP环节


    在安装摄像头之前你应该完成下面工作:
    1.下载客户端程序-仍然在虚拟机里面自带浏览器中下载本文提供的程序文件

    2.解压缩后将里面文件夹放于一个你能找到的文件夹,例如放在home中

    解压缩后将里面所有文件拷贝到拷贝到live/testProgs由于你当前目录为home/testRTSPClient那么就需要的拷贝命令为 cp ./testRTSPClient/* ./你的live目录的前一个目录/live/testProgs
    3.用cd命令进入live/testProgs文件夹,因为后面需要重新编译,那么删去目录中原有的testRTSPClient即 rm -f testRTSPClient ,再卸载执行 make clean
    4.为保证虚拟机与摄像头在同一网段,由于摄像头IP为192.168.1.200,那么不妨将虚拟机IP修改为192.168.1.8
    那么直接配置ifconfig eth0 192.168.1.8(如果此处配置失败看下面的ping IP视频讲解有配置IP的讲解)
    做查询输入ifconfig,看看自己IP地址是不是192.168.1.8?
    5.仍然在live/testProgs目录中 vim testRTSPClient.cpp 将里面的IP改为虚拟机IP,即将SERVER_IP修改为192.168.1.8
    修改地方如图:

    将RTSP地址修改为这个地址:rtsp://admin:fang123456@192.168.1.200/h264/ch1/main/av_stream
    如图位置:

    6.输入ESC和:wq!保存退出再make一下,注意make失败说明你当前目录错了,要在live/testProgs目录中。
    7.ls观察是否生成testRTSPClient

    此时你需要搞明白一共有那三个iP地址?如何ping他们,那么见下面视频


    8.运行它即 ./testRTSPClient 不能报错进行截图
    9.用VLC软件观察是否有实时h264流,进行播放
    观察流地址为rtsp://admin:fang123456@192.168.1.200/h264/ch1/main/av_stream填写到VLC软件中即可观察到
    如图所示
    THMZpF.md.png

    六、解码与播放环节


    1.liunx系统浏览器输入本站网址sciarm.com下载下面提供的播放器文件

    2.加压缩防止home文件夹下面即可
    3.vim include.h
    4.按a进入编辑将里面的ip修改为你配置过后的虚拟机IP,即将SERVER_IP 里面的IP修改为192.168.1.8,保持并退出
    5.再输入编译命令 gcc -o demo main.c fun_deco_display.c fun_others.c fun_recv_control.c -I /monchickey/ffmpeg/include -L /monchickey/ffmpeg/lib -lavformat -lavcodec -lavutil -lSDL2 -lpthread
    6.观察是否有demo文件生成

    七、最后工作

    两个TM终端一个在/live/testProgs文件夹中输入 ./testRTSPClient
    另一个TM终端在cd到第六步那个文件夹输入 ./demo
    观察播放器是否有实时画面出现如图所示:



    如有哪里不明白可与我联系

    32
    [嵌入式]使用apt安装命令遇到Could not get lock /var/lib/dpkg/lock解决方案
    « 上一篇 2021-12-28
    秋季的森林(自然声音)
    下一篇 » 2021-12-27

    评论 (0)

    取消