本阶段完成把ffplay移植到sdl2, PC上基本测试:图片,视频OK。
api 1.2
SDL_Surface *screen;
screen = SDL_SetVideoMode(w, h, 0, flags);
SDL_WM_SetCaption
SDL_FillRect
screen->format, w, h
SDL_UpdateRect
SDL_Overlay *bmp;
SDL_CreateYUVOverlay(screen);
SDL_LockYUVOverlay
bmp->pixels[i],pitches[i] //video_thread-->queue_picture; video_image_display-->blend_subrect
//video_refresh-->video_display-->video_image_display
SDL_DisplayYUVOverlay
api 2.0
SDL_Window *win;
SDL_CreateWindow, SDL_SetWindowSize, SDL_SetWindowTitle,
SDL_GetWindowSurface(win)->format,w,h
SDL_Renderer *render;
SDL_CreateRenderer(win), SDL_RenderClear, SDL_RenderCopy, SDL_RenderPresent
SDL_Texture *texture;
SDL_CreateTexture(render), SDL_LockTexture/transform/SDL_UnlockTexture, SDL_UpdateYUVTexture,
问题
Q. YUV格式转换。
A. LockTexture得到的pixel/pitch指向Y。YUV是紧凑排列,没有align,从而可推出U,V的data/pitch。
Q. ffplay a.png输出也是yuv420p ?
A. 是的。在configure_video_filters()设置filt_out的"pix_fmts"。调了vf_scale.c?
avfilter_graph_config-->
graph_config_formats-->query_formats-->"auto-inserted scaler %d"
SDL_Window -- physical pixels you see, 对应多个
SDL_Renderer -- store settings and context,对应多个
SDL_Texture -- resource, element。
Q: texture放到另一个视图显示。
main view -- composited layers
layer view -- individual layer
A:src = SDL_GetWindowSurface(src_win);
fmt = SDL_GetWindowPixelFormat(src_win);
SDL_RenderReadPixels(src_render, 0, fmt, src->pixels, src->pitch);
SDL_UpdateTexture(dst_render, src->pixels, src->pitch);
Q: resize,blend,colorkey?
A: SDL_RenderSetScale(sx, sy)/SDL_RenderCopy with diff rect,
SDL_SetTextureAlphaMod(a)/SDL_SetRenderDrawBlendMode(blend),
Q: 绿边处理duplicate_right_border_pixels().
A: SDL2是否还存在该问题?
render to texture
direct pixels operation
Q: 使用SDL2_Image,
SDL_Surface *s = IMG_Load("in.png");
SDL_Texture *t = SDL_CreateTextureFromSurface(render, s);
SDL_FreeSurface(s);
能不能直接操作纹理?
A: [1]的例子是针对ARGB,使用SDL_UpdateTexture(t,rect, pixels, pitch);
写像素,如果想读像素呢?
SDL_LockTexture(t, rect, &pixels, &pitch);
提供一个只写的像素指针。
而SDL_LockSurface(s)可以对s->pixels进行读写。
针对render的像素读取:
SDL_RenderReadPixels(r, rect, fmt, pixels, pitch);
Q: 因为视频宽高比和窗口宽高不同,四周留黑边,要fill_border-->fill_rectangle-->SDL_Fill/UpdateRect
A: SDL_SetRenderDrawColor(render, a,r,g,b);
4次SDL_RenderFillRect(render, rect);
1次SDL_RenderPresent(render);
跟据SDL2里面的注记,SDL_RenderPresent(render) 把backbuffer显示之后,
backbuffer不再有效,因此建议在新的绘制开始前SDL_RenderClear(),即使每个像素都重写。
于是fill_border代码完全可以省略。
改造计划
====
有人说LockTexture比UpdateYUVTexture慢。
那这里引入Lock是为了直接修改像素,字幕混合blend_subrect用的。
我们不必Lock,只要把字幕当成texture即可!
其实sdl2底层对YUV的处理也是用三个纹理来搞的。
screen --> win
bmp --> texture
blend_subrect --> SDL_UpdateYUVTexture(t,rect, Ydata, Ypitch,...);
剩下的事情是考虑graphics memory 有多大,
VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE配置多少。
调试
====
Q. SDL_CreateRenderer flag =SDL_RENDERER_SOFTWARE 没死, 0死在glEnable()。
A. 只能在主线程render。
把
video_thread-->queue_picture-->SDL_UpdateYUVTexture_REAL
移到主线程:
refresh_loop_wait_event-->video_refresh-->video_display-->video_image_display
实际上为了简单起见,在alloc_picture时就Update。
代码放在
https://github.com/DeYangLiu/ffmpeg-streaming/blob/master/ffplay2.c
TODO
全屏后左右两边是红边。
测试带字幕的视频。
ref
====
[1] http://www.programmersranch.com/2014/02/sdl2-pixel-drawing.html