嵌入式视频流指南-2021
我的学记|刘航宇的博客

嵌入式视频流指南-2021

刘航宇
4年前发布 /正在检测是否收录...
温馨提示:
本文最后更新于2022年11月29日,已超过848天没有更新,若内容或图片失效,请留言反馈。

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

目录

一、课题任务:

(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没安装看本站其他文章另外两个软件见下面链接
图片[1] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客

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

注意:这里三个文件下载后解压后仍然要解压,后文有TM终端解压命令,需要练习手法哦
下载后解压 图片[2] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
将第一个文件重命名,移动到其他文件夹
图片[3] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
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


图片[4] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
输入 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库安装成功,并可正常调用。
    你看到播放器图片应是这样:
    图片[5] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客

    四、检验UDP传输


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

    还是老规矩这些都放在一个你知道的文件夹中
    首先输入ifconfig 查看ip地址,如图所示:
    图片[6] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
    记下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文件!!
图片[7] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
UDP传输文件工作完成

五、摄像头与RTSP环节


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

2.解压缩后将里面文件夹放于一个你能找到的文件夹,例如放在home中
图片[8] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
解压缩后将里面所有文件拷贝到拷贝到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
修改地方如图:
图片[9] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
将RTSP地址修改为这个地址:rtsp://admin:fang123456@192.168.1.200/h264/ch1/main/av_stream
如图位置:
图片[10] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客

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
观察播放器是否有实时画面出现如图所示:
图片[11] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客
图片[12] - 嵌入式视频流指南-2021 - 我的学记|刘航宇的博客

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

© 版权声明
THE END
喜欢就支持一下吧
点赞 33 分享 赞赏
评论 抢沙发
取消