FFmpeg + SDL --- SDLビデオディスプレイ

第4章SDLビデオディスプレイ

この章を読む前に読むことをお勧めします:FFmpeg + SDL -----シラバス

目次

•ビデオディスプレイの知識
•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():ウィンドウを作成します
SDL_Window▫SDL_CreateRenderer():レンダラーを作成します
SDL_Renderer▫SDL_CreateTexture ():テクスチャの作成SDL_Texture▫SDL_UpdateTexture():テクスチャデータの
設定
▫SDL_RenderCopy():テクスチャデータをレンダラーにコピー
▫SDL_RenderPresent():
表示▫SDL_Delay():ユーティリティ関数。遅延に使用されます。
▫SDL_Quit():SDLシステムを終了します

SDLビデオディスプレイのデータ構造

1.SDLビデオディスプレイのデータ構造は次のとおりです。2。SDL
ここに画像の説明を挿入
データ構造の概要
▫SDL_Window:「ウィンドウ」を表し、ウィンドウは複数のビデオを同時に再生できます
▫SDL_Renderer:「レンダラー」を表します
▫SDL_Texture: 「テクスチャ」とテクスチャは実際にはYUVに対応します
▫SDL_Rect:単純な長方形の構造で、どこに描画されているかを確認します。1つだけでなく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