:) 本文主要是記錄入門(mén)SDL的時(shí)候遇到的一些問(wèn)題
首先要感謝雷神 --
SDL簡(jiǎn)介
- 一個(gè)用c語(yǔ)言寫(xiě)的庫(kù)先巴,主要用來(lái)操作視頻和音頻
- 是在將視頻和音頻解碼之后送往硬件的庫(kù)
大概梳理一下視頻播放的步驟
- 首先有概念要清楚,就是視頻文件中的聲音是送往音頻設(shè)備洛二,視頻是送往屏幕舱沧,但是音頻設(shè)備能識(shí)別的就是原始的采樣數(shù)據(jù)阀圾,而屏幕能識(shí)別的就是像素?cái)?shù)據(jù)。
- 平時(shí)我們遇到的視頻文件格式(MP4狗唉,F(xiàn)LV..)都是壓縮過(guò)后的數(shù)據(jù)初烘,壓縮過(guò)后空間占用更小。還有一點(diǎn)需要注意的是這些格式的文件都是同時(shí)又音頻和視頻數(shù)據(jù)
- 我們將視頻文件的數(shù)據(jù)解壓縮之后就能得到視頻數(shù)據(jù)和音頻數(shù)據(jù)分俯,這個(gè)過(guò)程稱(chēng)為解碼肾筐。這里就會(huì)涉及到各種的編碼算法,常見(jiàn)的音頻編碼就是acc缸剪,常見(jiàn)的視頻編碼就是h264台盯。也可以叫壓縮算法趁窃。 解碼之后我們就能達(dá)到acc編碼的音頻數(shù)據(jù),和h264編碼的視頻數(shù)據(jù)听哭,但是這些數(shù)據(jù)任然是壓縮的數(shù)據(jù)。
- 音頻的采樣數(shù)據(jù)格式是pcm疾宏,視頻的原始數(shù)據(jù)(未壓縮)是yuv,就是兩個(gè)文件格式,里面保存了音頻設(shè)備和視頻設(shè)備能夠直接使用的數(shù)據(jù)壮啊。把上面的acc和h264數(shù)據(jù)轉(zhuǎn)化成 pcm 和yuv數(shù)據(jù)之后就可以使用sdl庫(kù)將數(shù)據(jù)送往對(duì)應(yīng)的硬件設(shè)備。
SDL操作也比較固定(后面貼代碼)~
- 代碼就這幾個(gè)步驟
- 首先初始化
- 創(chuàng)建一個(gè)window(其實(shí)就是一個(gè)視屏依附的窗口)
- 創(chuàng)建一個(gè)Renderer
- 最后是創(chuàng)建一個(gè)Texture(不斷的給Texture賦值就可以了)
- 這里還有一個(gè)概念就是 Window和Renderer是一一對(duì)應(yīng)的撑蒜,但是Renderer和Texture不是一一對(duì)應(yīng)的哈歹啼。一個(gè)Renderer可以包含幾個(gè)Texture。也就是說(shuō)一個(gè)Window可以分成幾塊來(lái)顯示座菠。不同的快顯示不同的視屏狸眼。
說(shuō)說(shuō)Demo主要遇到的問(wèn)題(IDE是vs2015)
- _imp__iob_func 和 _imp__fprintf 解決辦法
錯(cuò)誤 LNK2019 無(wú)法解析的外部符號(hào) __imp____iob_func,該符號(hào)在函數(shù) _ShowError 中被引用 PalyerDemo E:\vsprojects\PalyerDemo\PalyerDemo\SDL2main.lib(SDL_windows_main.obj) 1
錯(cuò)誤 LNK2019 無(wú)法解析的外部符號(hào) __imp__fprintf浴滴,該符號(hào)在函數(shù) _ShowError 中被引用 PalyerDemo E:\vsprojects\PalyerDemo\PalyerDemo\SDL2main.lib(SDL_windows_main.obj) 1
warning LNK4098: 默認(rèn)庫(kù)“MSVCRT”與其他庫(kù)的使用沖突拓萌;請(qǐng)使用 /NODEFAULTLIB:library 解決辦法
還有個(gè)奇葩問(wèn)題msvcrt.dll 讀取位置 0x003BD000 時(shí)發(fā)生訪問(wèn)沖突。這個(gè)主要是自己的代碼問(wèn)題升略。(分配內(nèi)存的時(shí)候大小寫(xiě)錯(cuò)了)
Demo代碼吧(里面的yuv文件可以去雷神哪里下載)
#include "stdafx.h"
#include <stdio.h>
extern "C" {
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libswresample\swresample.h"
#include "libswscale\swscale.h"
FILE __iob_func[3] = { *stdin,*stdout,*stderr };
#include "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_h * pixel_h * bpp / 8];
int main(int argc, char* argv[]) { //這里的main函數(shù)的參數(shù)主要是sdl里面也有一個(gè)main函數(shù)
//yuv到屏幕的過(guò)程
//SDL Simple DirectMedia Layer
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("demo.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;
}
Nothing is certain in this life. The only thing i know for sure is that. I love you and my life. That is the only thing i know. have a good day