LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1742|回复: 9

请教,关于播放yuv序列的程序

[复制链接]
发表于 2006-5-21 15:37:35 | 显示全部楼层 |阅读模式
我用SDL写了一个播放YUV序列的程序,可是运行后窗口一直是黑的,什么都没有,哪位大侠知道是什么原因吗?
谢谢
程序如下:
[PHP]#include <SDL.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define W 176
#define H 144
#define FILENAME "foreman.qcif"

int
main()
{
  SDL_Surface *screen;
  SDL_Overlay* overlay;
  SDL_Rect overlayrect;
  int imgsize_y = W * H;
  int imgsize_uv = W * H / 4;
  int fd;
  int i;
  char *pic;
  int framesz = imgsize_y + 2 * imgsize_uv;

  if ((fd = open(FILENAME, O_RDONLY)) < 0) {
        perror("open");
        exit(1);
  }

  pic = malloc(framesz);
  if (NULL == pic) {
        fprintf(stderr, "memory allocation error occured.\n");
        exit(1);
  }



  /* Initialize the SDL library */
  if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
        fprintf(stderr,
                        "Couldn't initialize SDL: %s\n", SDL_GetError());
        exit(1);
  }

  /* Clean up on exit */
  atexit(SDL_Quit);
   
  /*
   * Initialize the display in a 640x480 8-bit palettized mode,
   * requesting a software surface
   */
  screen = SDL_SetVideoMode(W, H, 0, SDL_SWSURFACE);
  if ( screen == NULL ) {
        fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n",
                        SDL_GetError());
        exit(1);
  }

  overlay = SDL_CreateYUVOverlay(W, H, SDL_YV12_OVERLAY, screen);
  if (!overlay) {
        fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
        exit(1);
  }

  printf("Created %dx%dx%d %s %s overlay\n",overlay->w,overlay->h,overlay->planes,
                 overlay->hw_overlay?"hardware":"software",
                 overlay->format==SDL_YV12_OVERLAY?"YV12":
                 overlay->format==SDL_IYUV_OVERLAY?"IYUV":
                 overlay->format==SDL_YUY2_OVERLAY?"YUY2":
                 overlay->format==SDL_UYVY_OVERLAY?"UYVY":
                 overlay->format==SDL_YVYU_OVERLAY?"YVYU":
                 "Unknown");

  for(i=0; i<overlay->planes; i++) {
        printf("plane %d: pitch=%d\n", i, overlay->pitches);
  }

  overlayrect.x=0;
  overlayrect.y=0;
  overlayrect.w=W;
  overlayrect.h=H;

  i = 0;
  while (read(fd, pic, framesz) == framesz) {
        fprintf(stderr, "Frame: %d\n", ++i);
        SDL_LockSurface(screen);
        SDL_LockYUVOverlay(overlay);

        memcpy(overlay->pixels[0], pic, imgsize_y);
        memcpy(overlay->pixels[1], pic + imgsize_y, imgsize_uv);
        memcpy(overlay->pixels[2], pic + imgsize_y + imgsize_uv, imgsize_uv);

        SDL_UnlockYUVOverlay(overlay);
        SDL_UnlockSurface(screen);

        SDL_DisplayYUVOverlay(overlay, &overlayrect);

        SDL_Delay(200);
  }

  SDL_FreeYUVOverlay(overlay);
  free(pic);
  close(fd);


  return 0;
}
[/PHP]
 楼主| 发表于 2006-5-21 15:41:59 | 显示全部楼层
上传一个只有三帧的测试序列
将文件名改为foreman.qcif就可以了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2006-5-22 09:22:59 | 显示全部楼层
X11下的?会不会跟xv有关?
有没有设SDL_VIDEODRIVER环境变量?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-5-23 09:37:14 | 显示全部楼层
奇怪,今天早上重新运行发现可以播放了
只是颜色不对劲,偏绿了,截图抓不下来
回复 支持 反对

使用道具 举报

发表于 2006-5-23 11:13:03 | 显示全部楼层
试试I420格式的YUV overlay。
回复 支持 反对

使用道具 举报

发表于 2006-5-24 11:01:20 | 显示全部楼层
Post by nait
奇怪,今天早上重新运行发现可以播放了
只是颜色不对劲,偏绿了,截图抓不下来

如果图像能出来,颜色不对,就说明亮度信息是对了,色度信息不对。有可能是yuv格式的问题(yuv有多种格式),或者是在写程序时把uv的分量位置搞错了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-5-25 09:39:07 | 显示全部楼层
我确定测试的qcif文件中的yuv是4:2:0的,所以我创建了SDL_YV12_OVERLAY,其他格式的yuv我都还没搞明白
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-5-25 09:40:22 | 显示全部楼层
Post by kj501
如果图像能出来,颜色不对,就说明亮度信息是对了,色度信息不对。有可能是yuv格式的问题(yuv有多种格式),或者是在写程序时把uv的分量位置搞错了。

嗯,版主厉害,果真是把uv分量给搞反了,换一下位置就正确了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-5-25 09:43:45 | 显示全部楼层
还有一个奇怪的问题,我用fread代替了read,把程序拿到windows下去运行,就不对了。
程序可以正常编译运行,但得不到图像,同样的程序在linux下是好的,难道win下的fread做了什么特别的操作不成?
下面是修改后的代码
  1. #include <SDL.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <string.h>

  7. #define W 176
  8. #define H 144
  9. #define FILENAME "foreman_part_qcif.yuv"

  10. int
  11. main(int argc, char *argv[])
  12. {
  13.   SDL_Surface *screen;
  14.   SDL_Overlay *overlay;
  15.   SDL_Rect overlayrect;
  16.   size_t imgsize_y = W * H;
  17.   size_t imgsize_uv = W * H / 4;
  18.   FILE *f;
  19.   int i;
  20.   char *pic;
  21.   size_t framesz = imgsize_y + 2 * imgsize_uv;
  22.   char *filename;

  23.   if (2 == argc) {
  24.           filename = argv[1];
  25.   } else {
  26.           filename = FILENAME;
  27.   }

  28.   if ((f = fopen(filename, "rb")) == NULL) {
  29.     perror("fopen");
  30.     exit(1);
  31.   }

  32.   pic = malloc(framesz);
  33.   if (NULL == pic) {
  34.     fprintf(stderr, "memory allocation error occured.\n");
  35.     exit(1);
  36.   }



  37.   /* Initialize the SDL library */
  38.   if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  39.     fprintf(stderr,
  40.             "Couldn't initialize SDL: %s\n", SDL_GetError());
  41.     exit(1);
  42.   }

  43.   /* Clean up on exit */
  44.   atexit(SDL_Quit);
  45.      
  46.   /*
  47.    * Initialize the display
  48.    */
  49.   screen = SDL_SetVideoMode(W, H, 0, SDL_SWSURFACE);
  50.   if ( screen == NULL ) {
  51.     fprintf(stderr, "Couldn't set video mode: %s\n",
  52.             SDL_GetError());
  53.     exit(1);
  54.   }

  55.   overlay = SDL_CreateYUVOverlay(W, H, SDL_YV12_OVERLAY, screen);
  56.   if (!overlay) {
  57.     fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
  58.     exit(1);
  59.   }

  60.   printf("Created %dx%dx%d %s %s overlay\n",overlay->w,overlay->h,overlay->planes,
  61.          overlay->hw_overlay?"hardware":"software",
  62.          overlay->format==SDL_YV12_OVERLAY?"YV12":
  63.          overlay->format==SDL_IYUV_OVERLAY?"IYUV":
  64.          overlay->format==SDL_YUY2_OVERLAY?"YUY2":
  65.          overlay->format==SDL_UYVY_OVERLAY?"UYVY":
  66.          overlay->format==SDL_YVYU_OVERLAY?"YVYU":
  67.          "Unknown");

  68.   for(i=0; i<overlay->planes; i++) {
  69.     printf("plane %d: pitch=%d\n", i, overlay->pitches[i]);
  70.   }

  71.   overlayrect.x=0;
  72.   overlayrect.y=0;
  73.   overlayrect.w=W;
  74.   overlayrect.h=H;

  75.   i = 0;
  76.   while (1 == fread(pic, framesz, 1, f)) {
  77.     fprintf(stderr, "Frame: %d\n", ++i);
  78.     SDL_LockSurface(screen);
  79.     SDL_LockYUVOverlay(overlay);

  80.     memcpy(overlay->pixels[0], pic, imgsize_y);
  81.     memcpy(overlay->pixels[2], pic + imgsize_y, imgsize_uv);
  82.     memcpy(overlay->pixels[1], pic + imgsize_y + imgsize_uv, imgsize_uv);

  83.     SDL_UnlockYUVOverlay(overlay);
  84.     SDL_UnlockSurface(screen);

  85.     SDL_DisplayYUVOverlay(overlay, &overlayrect);

  86.     SDL_Delay(10000);

  87.   }

  88.   if (0 != ferror(f)) {
  89.           fprintf(stderr, "Read error\n");
  90.   }

  91.   SDL_FreeYUVOverlay(overlay);
  92.   free(pic);
  93.   fclose(f);

  94.   return 0;
  95. }
复制代码

百思不得其解
回复 支持 反对

使用道具 举报

发表于 2006-5-25 12:53:42 | 显示全部楼层
Post by nait
我确定测试的qcif文件中的yuv是4:2:0的,所以我创建了SDL_YV12_OVERLAY,其他格式的yuv我都还没搞明白

YV12不是I420。他们的Cb,Cr是反过来的。
看来你还需要补数字视频的基础知识啊。

看看运行目录下的stdout.txt和stderr.txt文件,可能有什么错误说不定。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表