📄 playh264.c
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <time.h>#include <getopt.h>#include <SDL/SDL.h>#include "h264.h"#include "perf.h"#define USE_X86_ASM#define BitsPerPixel 16void help(char *arg) { printf( "Usage: %s [<options>] <streamfile.264>\n" "<options> are:\n" " -h, -help Show this help\n" " -z, -zoom <n> Scale image by n\n" " -r, -fps <n> Set maximum frame rate to n fps\n" " -fps 0 Wait for keypress after each frame\n" " -f, -frames <n> Set maximum number of decoded frames\n" " -l, -loop Enable looping\n" " -b, -bench Benchmark mode\n" " -p, -perf Enable performance counting\n" ,arg);}static inline int clamp_and_scale(int i) {#ifdef USE_X86_ASM asm(" \ sarl $20, %%eax; \ cdq; \ notl %%edx; \ andl %%edx,%%eax; \ subl $256, %%eax; \ cdq; \ notl %%edx; \ orl %%edx,%%eax; \ andl $255, %%eax; \ ":"=a"(i):"a"(i):"%edx");#else i>>=20; if(i<0)i=0; if(i>255)i=255;#endif return i;}void showframe(SDL_Surface *screen, frame *f, int zoom) { int i,x,y,Y,Cb=0,Cr=0,R,G,B; unsigned char *pY,*pCb,*pCr; unsigned char *line;#if (BitsPerPixel==32)#define DEST_TYPE unsigned int DEST_TYPE cache;#define BytesPerPixel 4#endif#if (BitsPerPixel==24)#define DEST_TYPE unsigned char#define BytesPerPixel 3#endif#if (BitsPerPixel==15) || (BitsPerPixel==16)#define DEST_TYPE unsigned short DEST_TYPE cache;#define BytesPerPixel 2#endif DEST_TYPE *dest; perf_enter("rendering"); SDL_LockSurface(screen); line=screen->pixels; for(y=0; y<f->Lheight; ++y) { pY=&L_pixel(f,0,y); pCb=&Cb_pixel(f,0,y>>1); pCr=&Cr_pixel(f,0,y>>1); dest=(DEST_TYPE *)line; for(x=0; x<f->Lwidth; ++x) { Y=*pY++; if(!(x&1)) { Cb=*pCb++; Cr=*pCr++; } { int Y1,Pb,Pr; Y1= (Y-16) *1225732; Pb=(Cb-128)*1170; Pr=(Cr-128)*1170; R=clamp_and_scale(Y1 +1436*Pr); G=clamp_and_scale(Y1- 352*Pb -731*Pr); B=clamp_and_scale(Y1+1815*Pb); }#if (BitsPerPixel==32) cache=(R<<16)|(G<<8)|B; for(i=zoom; i; --i) *dest++=cache;#endif#if (BitsPerPixel==24) for(i=zoom; i; --i) { *dest++=B; *dest++=G; *dest++=R; }#endif#if (BitsPerPixel==16) cache=((R>>3)<<11)|((G>>2)<<5)|(B>>3); for(i=zoom; i; --i) *dest++=cache;#endif#if (BitsPerPixel==15) cache=((R>>3)<<10)|((G>>3)<<5)|(B>>3); for(i=zoom; i; --i) *dest++=cache;#endif } dest=(DEST_TYPE *)line; line+=screen->pitch; for(i=zoom; i>1; --i) { memcpy(line,dest,f->Lwidth*zoom*BytesPerPixel); line+=screen->pitch; } } SDL_UnlockSurface(screen); SDL_UpdateRect(screen,0,0,0,0);}void do_bench(int maxframe) { int frames=0; struct timeval start,end; double tdiff; printf("Benchmarking ...\n"); gettimeofday(&start,NULL); for(frames=0; h264_decode_frame(1); ++frames) { if(maxframe && frames>=maxframe) break; putchar('\r'); fflush(stdout); } gettimeofday(&end,NULL); tdiff=end.tv_sec-start.tv_sec+0.000001*(end.tv_usec-start.tv_usec); printf("%d frames decoded in %.1f seconds\n= %.1f ms/frame = %.1f fps\n", frames,tdiff,1000.0*tdiff/frames,frames/tdiff); h264_close(); perf_summarize(); exit(0);}int main(int argc, char *argv[]) { SDL_Surface *screen; SDL_Event ev; int width,height,zoom=1,loop=0,delay=40,bench=0,perf=0,maxframe=0; int pause=0,step=0,have_event; int info; int next_dts; char *filename=NULL; ///// Command Line Parameter Parsing //////////////////////////////////////// const static struct option options[]={ {"help", 0, NULL, 'h'}, {"scale", 1, NULL, 'z'}, {"zoom", 1, NULL, 'z'}, {"xy", 1, NULL, 'z'}, {"fps", 1, NULL, 'r'}, {"frames", 1, NULL, 'f'}, {"loop", 0, NULL, 'l'}, {"bench", 0, NULL, 'b'}, {"perf", 0, NULL, 'p'}, {0, 0, 0, 0} }; for(;;) { int res,longidx; res=getopt_long_only(argc,argv,"hz:r:f:lbp",options,&longidx); if(res==-1) break; switch(res) { case 'h': help(argv[0]); return 0; case 'l': loop^=1; break; case 'b': bench^=1; break; case 'p': perf^=1; break; case 'z': zoom=atoi(optarg); if(zoom<1 || zoom>10) { fprintf(stderr,"%s: invalid zoom value `%s'\n",argv[0],optarg); return 1; } break; case 'r': delay=atoi(optarg); if(delay<0 || delay>255) { fprintf(stderr,"%s: invalid fps value `%s'\n",argv[0],optarg); return 1; } if(delay) delay=1000/delay; break; case 'f': maxframe=atoi(optarg); if(delay<0) { fprintf(stderr,"%s: invalid frame count value `%s'\n",argv[0],optarg); return 1; } break; case '?': break; case ':': default: return 1; } } if(optind>=argc) { fprintf(stderr,"%s: no filename specified\n",argv[0]); return 1; } filename=argv[optind]; ///// Initialization //////////////////////////////////////////////////////// info=h264_open(filename); if(!info) return 1; width=H264_WIDTH(info); height=H264_HEIGHT(info); if(perf) perf_enable(); if(bench) do_bench(maxframe); printf("H.264 stream: %dx%d, zooming to %dx%d\n", width,height,width*zoom,height*zoom); if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)) { fprintf(stderr,"%s: Error in SDL_Init: %s\n",argv[0],SDL_GetError()); return 1; } atexit(SDL_Quit); SDL_WM_SetCaption(filename,"KeyJ's H.264 Viewer"); screen=SDL_SetVideoMode(width*zoom,height*zoom,BitsPerPixel,SDL_HWSURFACE); if(!screen) { fprintf(stderr,"%s: Error in SDL_SetVideoMode: %s\n",argv[0],SDL_GetError()); return 1; } ///// Main Loop ///////////////////////////////////////////////////////////// printf("Hint: "); if(delay) printf("[Space] toggles pause; "); printf("[Enter] advances to next frame\n"); pause=(!delay); step=1; next_dts=SDL_GetTicks(); for(;;) { if((!pause) || step) { frame *f; printf("\r"); f=h264_decode_frame(1); fflush(stdout); if(maxframe && h264_frame_no()>=maxframe) break; if(f) showframe(screen,f,zoom); else if(loop) { h264_rewind(); f=h264_decode_frame(1); fflush(stdout); if(!f) return 1; showframe(screen,f,zoom); } else break; next_dts+=delay; if(step) step=0; } if(!pause) { int wait=next_dts-SDL_GetTicks(); if(wait>0) SDL_Delay(wait); } if(pause) { if(!SDL_WaitEvent(&ev)) break; have_event=1; } else have_event=SDL_PollEvent(&ev); if(have_event) { if(ev.type==SDL_QUIT || (ev.type==SDL_KEYDOWN && (ev.key.keysym.sym==SDLK_ESCAPE || ev.key.keysym.sym==SDLK_q))) break; if(ev.type==SDL_KEYDOWN && ev.key.keysym.sym==SDLK_RETURN) step=1; if(delay && ev.type==SDL_KEYDOWN && ev.key.keysym.sym==SDLK_SPACE) pause^=1; } } printf("\nDecoding done.\n"); h264_close(); perf_summarize(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -