zoukankan      html  css  js  c++  java
  • yuv文件并行解析播放

    #include <stdio.h>
    #include <SDL2/SDL.h>
    #include <sys/time.h>
    #include <time.h>
    #include <mpi.h>
    #include <signal.h>
    
    
    int dest;
    const int bpp=24;  //bits per pixel 像素深度
    //用24个二进制位来表示颜色,此时能表示16777216种颜色
    //RGB三种颜色各自的精度都更高了(RGB各8位),叫RGB888,也叫RGB24 
    
    int screen_w=500,screen_h=500; //窗口高度和宽度 
    const int pixel_w=176*2,pixel_h=144*2;  //图片分辨率 
    double difftimeval(const struct timeval *start, const struct timeval *end) 
    { //计算时间差的函数 参数分别是起始时间和结束时间 
            double d;
            time_t s;  //
            suseconds_t u; //微秒
    
            s = start->tv_sec - end->tv_sec;  
            u = start->tv_usec - end->tv_usec;
            //if (u < 0)
            //        --s;
    
            d = s;
            d *= 1000000.0;  //1秒=10^6秒 
            d += u;
    
            return d;
    }
    
    //将RGB24 / BGR24转换为RGB32 / BGR32
    //并在需要时更改Endian
    //big endian 数据存储:高字节在低地址, 低字节在高地址
    //small endian 数据存储:高字节在高地址, 低字节在低地址 
    void CONVERT_24to32(unsigned char *image_in,unsigned char *image_out,int w,int h){
        int i,j;
        for(i =0;i<h;i++)
            for(j=0;j<w;j++){
            //内存中的ARGB格式大字节序(低地址保存高MSB,这里是A):A | R | G | B 
            //ARGB格式Little Endian(低地址,低MSB,这里是B)在内存中:B | G | R | A 
                //Big Endian or Small Endian
                //"ARGB" order:high bit -> low bit.
                if(SDL_BYTEORDER==SDL_LIL_ENDIAN){ //如果是内存中的rgb格式是小端 
                    //Little Endian (x86): R|G|B --> B|G|R|A
                    image_out[(i*w+j)*4+0]=image_in[(i*w+j)*3+2];
                    image_out[(i*w+j)*4+1]=image_in[(i*w+j)*3+1];
                    image_out[(i*w+j)*4+2]=image_in[(i*w+j)*3];
                    image_out[(i*w+j)*4+3]='0';
                }else{ //如果是内存中的rgb格式是大端 
                    //Big Endian: R|G|B --> A|R|G|B
                    image_out[(i*w+j)*4]='0';
                    memcpy(image_out+(i*w+j)*4+1,image_in+(i*w+j)*3,3);  //从存储区image_in+(i*w+j)*3复制3个字符到存储区image_out+(i*w+j)*4+1 
                }
            }
    }
    //Refresh Event
    #define REFRESH_EVENT  (SDL_USEREVENT + 1)
     
    int thread_exit=0;
     
     //事件队列自身是由一系列的SDL_Event结构体组成,一个SDL_Event对应一个等待事件
    int refresh_video(void *opaque){
        while (thread_exit==0) {   //SDL_Event是个联合体,是SDL中所有事件处理的核心
            SDL_Event event;
            event.type = REFRESH_EVENT;
            SDL_PushEvent(&event);
            SDL_Delay(50);
        }
        return 0;
    }
     
    int main(int argc, char* argv[])
    {
        struct timeval start,end;
        gettimeofday(&start,NULL);  //SDL2库函数,计算时间差 
        printf("start: %f
    %f
    ",start.tv_sec,start.tv_usec); //开始的时间(分别以秒和微秒的形式来表示) 
        int blocks = pixel_h*pixel_w/176/144;  //每一块的大小 
        int c = 9999; //the sum
        int num ;
        int myrank;
        unsigned char buffer[pixel_w*pixel_h*bpp/8];//middle 
        //BPP=32
        unsigned char buffer_convert[pixel_w*pixel_h*4];//big
        unsigned char yuv_buffer[pixel_w*pixel_h*bpp/8/2]; //small
        signal(2,SIG_DFL);
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
        MPI_Comm_size(MPI_COMM_WORLD, &num);//返回通信的进程数 
        //unsigned char yuv_buffer[pixel_w*pixel_h*bpp/8/2];
        
        //printf("num is %d
    ",num);
        //printf("myrank is %d
    ",myrank);
        
    
        if(myrank ==0)
        {
            printf("I am (0):%d
    ",myrank);
            c=0;
            FILE *fp=NULL;
    
            fp=fopen("x.yuv","rb+");  //打开一个yuv格式的文件 
    
            if(fp==NULL){
                printf("cannot open this file
    ");
                return -1;
            }
            while(1)
            {
            
                if (fread(yuv_buffer, 1, pixel_w*pixel_h*bpp/8/2, fp) != pixel_w*pixel_h*bpp/8/2) //fread函数返回值是实际读取元素的数目 
                { //yuv_buffer:读取的数据存放的内存的指针 
                  //1:每次读取的字节数 
                  //pixel_w*pixel_h*bpp/8/2:读取的次数 
                    // Loop
                    break;    
                }
            /*int m=0;
            for(;m<1000;m++){
                printf("%d ",yuv_buffer[m]);
            }if(m!=0&&m%100==0)printf("
    ");*/
                    //num 0: process broadcast
                    c++;
                    dest = (c-1)%(num-1)+1;  //目标进程的rank值 
                    int f=0;
                    for(;f<blocks;f++)//将图片分配到所有的进程 
                        MPI_Send(yuv_buffer+f*pixel_w*pixel_h*bpp/8/2/blocks,pixel_w*pixel_h*bpp/8/2/blocks,MPI_CHAR,dest,0,MPI_COMM_WORLD);
                        //第一次发送的是每一帧图片 
                        //yuv_buffer+f*pixel_w*pixel_h*bpp/8/2/blocks:发送缓冲区的起始地址 
                        //pixel_w*pixel_h*bpp/8/2/blocks:需要发送信息的元素个数 
                        //MPI_CHAR:发送消息的数据类型 
                        //dest:目标进程的rank号 
            }
            printf("read finished!
    ");
        //printf("c is %d
    ",c);
        }
    
    //MPI_BCAST是从一个序列号为0的进程将一条消息广播发送到组内的所有进程  
        MPI_Bcast(&c,1,MPI_INT,0,MPI_COMM_WORLD);
        
        if(myrank==0)
        {
            //SDL_Init是SDL运行的初始 
            if(SDL_Init(SDL_INIT_VIDEO)) { //初始化视频子系统 
                printf( "Could not initialize SDL - %s
    ", SDL_GetError()); 
                return -1;
            } 
            SDL_Window *screen; 
            //SDL 2.0 Support for multiple windows
            screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
                //SDL_CreateWindow函数参数分别表示:窗口标题、窗口x、y坐标、窗口的宽和高以及一些其他属性 
            if(!screen) {  
                printf("SDL: could not create window - exiting:%s
    ",SDL_GetError());  
                return -1;
            }
            //创建窗口渲染器 
            SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);  
            //screen指渲染的目标窗口,设置“-1”则初始化默认的渲染设备,最后一个参数为0默认使用SDL_RENDERER_ACCELERATED(使用硬件加速) 
            Uint32 pixformat=0;
            pixformat= SDL_PIXELFORMAT_BGR888;  //创建纹理的格式 
            SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);
            //sdlRenderer:目标渲染器   pixformat:纹理的格式 
            //SDL_TEXTUREACCESS_STREAMING:变化频繁 
            
            SDL_Rect sdlRect;  
            SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
            SDL_Event event;
            int source =1;
            //printf("c is %d
    ",c);
            while(1)
            {
                SDL_WaitEvent(&event);
                if(event.type==REFRESH_EVENT)
                {
    
                //Process 0 accepts buffer in turn 
                //printf ("wait %d return
    ",(source - 1)%(num-1)+1);
                    int f = 0;
                    for(;f<blocks;f++)
                    {
                        MPI_Recv(buffer_convert+f*pixel_w*pixel_h*4/blocks,pixel_w*pixel_h*4/blocks,MPI_CHAR,(source - 1)%(num-1)+1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE); //accepting buffer_convert
                        //第一个参数:接收缓冲区的起始地址  第二个参数:需要接收元素的个数  (source - 1)%(num-1)+1:源进程的rank值
                    }
                    //printf(" accept %d finished
    ",(source - 1)%(num-1)+1);
                        
                    SDL_UpdateTexture( sdlTexture, NULL, buffer_convert, pixel_w*4);  
                    //sdlTexture:目标纹理   buffer_convert:像素数据   pixel_w*4:一行像素数据的字节数 
                    if(source == c)
                    {
                        //printf("exit!!!!00000000000000
    ");
                        break;
                    }
                    source++;
                    //printf("source !!!!%d
    ",source);
                    //FIX: If window is resize
                    sdlRect.x = 0;  
                    sdlRect.y = 0;  
                    sdlRect.w = screen_w;  
                       sdlRect.h = screen_h;  
                
                    SDL_RenderClear( sdlRenderer );   
                    SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);  
                    SDL_RenderPresent( sdlRenderer );  
                
                }
                else if(event.type==SDL_WINDOWEVENT){
                    //If Resize
                    SDL_GetWindowSize(screen,&screen_w,&screen_h);
                }
                else if(event.type==SDL_QUIT){
                    break;
                }
    
            }
        }
        else if(myrank!=0)  
    //pYUV = yuv_buffer pBGR24 = buffer width= pixel_w  height= pixel_h
        {
            int count =0;  //Number of frames made by each process
            //每个进程处理的帧数目 
            while(1)
            {
                if(myrank <= c%(num-1))  //num是进程总数    
                {                 
                    if(count == (c/(num-1))+1)
                    {                
                    break;
                    }
                }
                else
                {
                    //printf("xxxx%d
    ",c/(num-1));
                    if(count == (c/(num-1)))
                    {
                    //printf("count weituichu%d
    ",count);
                    //printf("%d myrank exit
    ",myrank);
                    break;
                    }
                }
                int f=0;
                for(;f<blocks;f++)
                {
                    MPI_Recv(yuv_buffer+f*pixel_w*pixel_h*bpp/8/2/blocks,pixel_w*pixel_h*bpp/8/2/blocks,MPI_CHAR,0,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE); 
                    //收到一些图片帧 
                }
                printf("%d accept finished
    ",myrank);
                if (pixel_w  < 1 || pixel_h < 1 || yuv_buffer == NULL ||  buffer == NULL)
                    return 0;
                const long len = pixel_w * pixel_h;
                unsigned char* yData = yuv_buffer;
                unsigned char* uData = &yData[len];
                unsigned char* vData = &uData[len >> 2];
                
                int bgr[3];
                int yIdx,uIdx,vIdx,idx;
                int i,j,k;
            
                for(i=0;i<pixel_h;i++)
                    for (j = 0;j < pixel_w;j++){
                        yIdx = i * pixel_w + j;
                        vIdx = (i/2) * (pixel_w/2) + (j/2);
                        uIdx = vIdx;
            
                        //计算rgb  yuv解码  yuv采用4:2:2方式采样 
                        bgr[0] = (int)(yData[yIdx] + 1.732446 * (uData[vIdx] - 128));                                     // b weight
                        bgr[1] = (int)(yData[yIdx] - 0.698001 * (uData[uIdx] - 128) - 0.703125 * (vData[vIdx] - 128));    // g weight
                        bgr[2] = (int)(yData[yIdx] + 1.370705 * (vData[uIdx] - 128));                                     // r weight
                        
                        for (k = 0;k < 3;k++){
                            idx = (i * pixel_w  + j) * 3 + k;
                            if(bgr[k] >= 0 && bgr[k] <= 255)
                                buffer[idx] = bgr[k];
                            else
                                buffer[idx] = (bgr[k] < 0)?0:255;
                        }
                    }
    
                    CONVERT_24to32(buffer,buffer_convert,pixel_w,pixel_h);
                    //buffer_convert return to process 0
                    //printf("%dtranscode finished 
    ",myrank);
                    for(f=0;f<blocks;f++)
                    {
                        MPI_Send(buffer_convert+f*pixel_w*pixel_h*4/blocks,pixel_w*pixel_h*4/blocks,MPI_CHAR,0,0,MPI_COMM_WORLD);
                        //第二次发送,发送的数据是每一帧里面的数据 
                    }
                    count++;
                    printf("%dsend to process 0 
    ",myrank);
            }
            
        }
        gettimeofday(&end, NULL);  //get the end_time
        //计算结束的时间 
        printf("myrank %d exit
    ",myrank);
        if(myrank == 0)
        printf("%.0f
    ", difftimeval(&end, &start));  //计算时间的函数 
          MPI_Finalize();
        return 0;
    }
  • 相关阅读:
    HDU-4035 Maze
    poj 3744 Scout YYF I
    HDU 4911 Inversion
    HDU-3001 Travelling
    HDU 4539 郑厂长系列故事——排兵布阵
    poj 3311 Hie with the Pie
    poj-1185 炮兵阵地
    位运算
    HDU-1438 钥匙计数之一
    poj 3254 Corn Fields
  • 原文地址:https://www.cnblogs.com/Stephen-Jixing/p/12128562.html
Copyright © 2011-2022 走看看