FFmpeg + SDL --- SDL 비디오 디스플레이

4 장 SDL 비디오 디스플레이

이 장을 읽기 전에 읽어 보는 것이 좋습니다 : FFmpeg + SDL ----- Syllabus

목차

• 비디오 디스플레이 지식
• SDL 소개
• SDL 개발 환경에서 VC 설정
• 샘플 프로그램 실행
• 기능 SDL 비디오 디스플레이
• SDL 비디오 디스플레이 데이터 구조
• 고급-샘플 프로그램 실행
• 고급 - 멀티 스레딩 및 이벤트에서 SDL
• 연습

비디오 디스플레이 지식

비디오 디스플레이 프로세스 : 비디오 디스플레이 프로세스는 화면에 픽셀 데이터를 "그리는"프로세스입니다. 예를 들어 YUV를 표시하는 것은 시스템 창에 YUV를 "그리는"것입니다.

SDL 소개

  • 효과
    • SDL (Simple DirectMedia Layer) 라이브러리의 기능은 복잡한 비디오 및 오디오 하단 대화 형 작업을 캡슐화하고 비디오 및 오디오 처리의 어려움을 단순화하는 것입니다.
    • 이 과정은 SDL 라이브러리의 일부인 비디오 표시 부분 만 포함합니다. (이 라이브러리는 주로 게임 개발에 사용됩니다.)
  • 풍모
    • 크로스 플랫폼, 프로그램은 여러 플랫폼에서 사용할 수 있습니다.
    • 오픈 소스
  • 구조
    • SDL 구조는 다음과 같습니다. 하드웨어와의 상호 작용을 완료하기 위해 실제로 DirectX와 같은 기본 API를 호출하는 것을 볼 수 있습니다. 다른 시스템에 따라 해당 API를 호출하십시오.
      여기에 사진 설명 삽입

VC하에 SDL 개발 환경 구축

  • 새 콘솔 프로젝트
    • VC ++ 열기
    • 파일-> 새로 만들기-> 프로젝트-> Win32 콘솔 응용 프로그램
  • SDL 개발 파일 복사
    • 헤더 파일 (* .h)을 프로젝트 폴더의 포함 하위 폴더에 복사합니다.
    • 라이브러리 파일 (* .lib)을 가져 와서 프로젝트 폴더의 lib 하위 폴더에 복사합니다.
    • 동적 라이브러리 파일 (* .dll)을 프로젝트 폴더에 복사합니다.
  • 개발 파일 구성
    • 속성 패널을 엽니 다.
      • 솔루션 탐색기-> 프로젝트를 마우스 오른쪽 버튼으로 클릭-> 속성
  • 헤더 파일 구성
    • 구성 속성-> C / C + ±> 일반-> 추가 포함 디렉토리, "include"입력 (지금 방금 파일이 복사 된 디렉토리)
  • 라이브러리 구성 가져 오기
    • 속성 구성-> 링커-> 일반-> 추가 라이브러리 디렉토리, "lib"입력 (지금 방금 파일이 복사 된 디렉토리)
    • 구성 속성-> 링커-> 입력-> 추가 종속성, 입력 "SDL2.lib; SDL2main.lib"(가져온 라이브러리의 파일 이름)
  • 동적 라이브러리를 구성 할 필요가 없습니다.

테스트

  • 소스 코드 파일 생성
    • 프로젝트에서 main () 함수를 포함하는 C / C ++ 파일을 만들고 (이미있는 경우이 단계를 건너 뛸 수 있음) 후속 단계에서이 파일에 소스 코드를 작성합니다.
  • 헤더 파일 포함
    • SDL이 C 언어로 사용되는 경우 다음 코드를 사용하십시오.
      #include“SDL2 / SDL.h”
    • SDL이 C ++ 언어로 사용되는 경우 다음 코드를 사용하십시오.
      extern "C"
      { #include "SDL2 / SDL.h" }

  • SDL 인터페이스 함수는 main ()에서 호출됩니다. 예를 들어 다음 코드는 SDL을 초기화합니다.
int main(int argc, char* argv[]){
	if(SDL_Init(SDL_INIT_VIDEO)) { 
		printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
	} else{
		printf("Success init SDL");
	}
	return 0;
}

작업이 정확하면 SDL이 구성되었음을 의미합니다.

샘플 프로그램 실행

SDL 비디오 디스플레이 기능

1. SDL 영상 표시 흐름도는 아래와 같습니다
여기에 사진 설명 삽입
. 2. SDL 영상 표시 기능 소개
▫ SDL_Init () : SDL 시스템 초기화
▫ SDL_CreateWindow () : 창 생성 SD L_Window
▫ SDL_CreateRenderer () : 렌더러 생성 SDL_Renderer
▫ SDL_CreateTexture () : 텍스처 생성 SDL_Texture
▫ SDL_UpdateTexture () :
텍스처 데이터 설정 ▫ SDL_RenderCopy () : 텍스처 데이터를 렌더러에 복사
▫ SDL_RenderPresent () :
display▫ SDL_Delay () : 유틸리티 함수, 지연에 사용됩니다.
▫ SDL_Quit () : SDL 시스템 종료

SDL 비디오 디스플레이 데이터 구조

1. SDL 비디오 디스플레이의 데이터 구조는 다음과 같습니다
여기에 사진 설명 삽입
. 2. SDL 데이터 구조 소개
▫ SDL_Window : "창"을 나타내며, 창은 동시에 여러 비디오를 재생할 수 있습니다
.▫ SDL_Renderer : "렌더러"를
나타냅니다. ▫ SDL_Texture : "텍스처"와 텍스처는 실제로 YUV에 해당합니다
.▫ SDL_Rect : 단순한 직사각형 구조, 그려지는 위치를 확인합니다. 하나가 아닌 2 * 2 형태 일 수 있습니다.

소스 코드 1 :

#include <stdio.h>

extern "C"
{
#include "sdl/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];

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;  

	while(1){
			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);  

			/* 修改下面的值可以调节视频显示的坐标,修改为多分割显示不同的码流 */
			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 );  
			//Delay 40ms
			SDL_Delay(40);
			
	}
	SDL_Quit();
	return 0;
}

SDL의 고급 이벤트 및 멀티 스레딩

1. SDL 멀티 스레딩
함수
 SDL_CreateThread () : 스레드 생성
▫ 데이터 구조
 SDL_Thread : 스레드 핸들
2. SDL 이벤트
▫ 함수
 SDL_WaitEvent () 이벤트 대기
 SDL_PushEvent () 이벤트 전송
▫ 데이터 구조
 SDL_Event : 표현 이벤트

고급 소스 코드

화면 너비를 수동으로 늘리기 위해 새 스레드가 추가되고 그에 따라 비디오 크기도 동적으로 조정됩니다.

#include <stdio.h>

extern "C"
{
#include "sdl/SDL.h"
};

const int bpp=12;

int screen_w=500,screen_h=500;
const int pixel_w=320,pixel_h=180;

unsigned char buffer[pixel_w*pixel_h*bpp/8];

//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit=0;

int refresh_video(void *opaque){
	thread_exit=0;
	while (thread_exit==0) {
		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("test_yuv420p_320x180.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;			//修改全局变量,下一次循环接收到的事件是BREAK_EVENT,然后退出整个循环过程
		}else if(event.type==BREAK_EVENT){
			break;
		}
	}
	SDL_Quit();
	return 0;
}

추천

출처blog.csdn.net/weixin_37921201/article/details/89367499