06-流媒体-YUV数据在SDL控件显示

整体方案:
采集端:摄像头采集(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 <stdio.h>
 
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在chi-cdk中,可以使用MediaCodec类和MediaExtractor类来获取yuv420格式的图像。具体步骤如下: 1. 创建一个MediaExtractor对象并设置要解码的视频文件路径: ``` MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(filePath); ``` 2. 找到包含视频流的轨道: ``` int trackIndex = -1; for (int i = 0; i < extractor.getTrackCount(); i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { trackIndex = i; break; } } ``` 3. 选择并配置要解码的轨道: ``` extractor.selectTrack(trackIndex); MediaFormat format = extractor.getTrackFormat(trackIndex); String mime = format.getString(MediaFormat.KEY_MIME); MediaCodec codec = MediaCodec.createDecoderByType(mime); codec.configure(format, null, null, 0); codec.start(); ``` 4. 循环读取每个视频帧并解码: ``` ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] outputBuffers = codec.getOutputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); boolean isEOS = false; while (!isEOS) { int inIndex = codec.dequeueInputBuffer(1000); if (inIndex >= 0) { ByteBuffer buffer = inputBuffers[inIndex]; int sampleSize = extractor.readSampleData(buffer, 0); if (sampleSize < 0) { codec.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isEOS = true; } else { codec.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0); extractor.advance(); } } int outIndex = codec.dequeueOutputBuffer(info, 1000); switch (outIndex) { case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: outputBuffers = codec.getOutputBuffers(); break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: format = codec.getOutputFormat(); break; case MediaCodec.INFO_TRY_AGAIN_LATER: break; default: ByteBuffer buffer = outputBuffers[outIndex]; // 这里的buffer即为yuv420的图像数据 codec.releaseOutputBuffer(outIndex, true); break; } } ``` 通过以上步骤,就可以获取到yuv420格式的图像数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值