整体方案:
采集端:摄像头采集(YUV)->编码(YUV转H264)->写封装(H264转FLV)->RTMP推流
客户端:RTMP拉流->解封装(FLV转H264)->解码(H264转YUV)->YUV显示(SDL2)
YUV视频是通过SDL控件显示,首先要编译SDL库。
SDL2库源码:https://download.csdn.net/download/sishen4199/88547680
$ ./configure --prefix=/home/zg/zg_code/zg_test/video_ref/SDL/SDL2-2.28.5/build_lib
make
make install
#include
extern "C"
{
#include "SDL2/SDL.h"
};
const int bpp=12;
int screen_w=640,screen_h=360;
const int pixel_w=640,pixel_h=360;
unsigned char buffer[pixel_w*pixel_h*bpp/8];
//Refresh Event
#define REFRESH_EVENT (SDL_USEREVENT + 1)
#define BREAK_EVENT (SDL_USEREVENT + 2)
int thread_exit=0;
int refresh_video(void *opaque){
thread_exit=0;
while (!thread_exit) {
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(40);
}
thread_exit=0;
//Break
SDL_Event event;
event.type = BREAK_EVENT;
SDL_PushEvent(&event);
return 0;
}
int main(int argc, char* argv[])
{
if(SDL_Init(SDL_INIT_VIDEO)) {
printf( "Could not initialize SDL - %s\n", 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);
if(!screen) {
printf("SDL: could not create window - exiting:%s\n",SDL_GetError());
return -1;
}
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
Uint32 pixformat=0;
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
pixformat= SDL_PIXELFORMAT_IYUV;
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);
FILE *fp=NULL;
fp=fopen("sintel_640_360.yuv","rb+");
if(fp==NULL){
printf("cannot open this file\n");
return -1;
}
SDL_Rect sdlRect;
SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
SDL_Event event;
while(1){
//Wait
SDL_WaitEvent(&event);
if(event.type==REFRESH_EVENT){
if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){
// Loop
fseek(fp, 0, SEEK_SET);
fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);
}
SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);
//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){
thread_exit=1;
}else if(event.type==BREAK_EVENT){
break;
}
}
SDL_Quit();
return 0;
}
PRJ_PATH = .
TARGETS = video_prj
DIR_INC = ./inc
DIR_SRC = ./src
DIR_OBJ = ./obj
CXX = g++
SRC := $(wildcard ${DIR_SRC}/*.cpp)
OBJ := $(patsubst ${DIR_SRC}/%.cpp,$(DIR_OBJ)/%.o,$(SRC))
FFMPEG_LIB_DIR = $(PRJ_PATH)/third_lib/ffmpeg/lib
FFMPEG_INC_DIR = $(PRJ_PATH)/third_lib/ffmpeg/include
SDL_LIB_DIR = $(PRJ_PATH)/third_lib/SDL/lib
SDL_INC_DIR = $(PRJ_PATH)/third_lib/SDL/include
INCLUDES = -I$(DIR_INC)
INCLUDES += -I$(FFMPEG_INC_DIR)
INCLUDES += -I$(SDL_INC_DIR)
LDFLAGS = -ldl -lpthread -lm
LDFLAGS += -lX11 -lasound -lmp3lame -lz -lrt
LDFLAGS += -L$(FFMPEG_LIB_DIR) -lavformat -lavdevice -lavcodec -lavutil -lavfilter -lpostproc -lswresample -lswscale
LDFLAGS += -L$(SDL_LIB_DIR) -lSDL2
CXXFLAGS = -fpermissive
CXXFLAGS += -fPIC
CFLAGS += $(INCLUDES)
$(TARGETS):$(OBJ)
$(CXX) $^ -o $@ $(LDFLAGS) $(CXXFLAGS)
$(DIR_OBJ)/%.o:$(DIR_SRC)/%.cpp
$(CXX) $(CFLAGS) -c $< -o $@ $(CXXFLAGS)
clean:
rm -f $(TARGETS)
rm -f $(DIR_OBJ)/*.o
完整工程:https://download.csdn.net/download/sishen4199/88547724