C++ sdl實(shí)現(xiàn)渲染旋轉(zhuǎn)視頻的方法分享
前言
一般情況下播放視頻時(shí)不需要旋轉(zhuǎn),但是如果是移動(dòng)端錄制的視頻有時(shí)會(huì)出現(xiàn)rotate參數(shù),且視頻寬高也是互換的,如果直接渲染則會(huì)出現(xiàn)視頻90度倒轉(zhuǎn)的問(wèn)題。所以渲染視頻時(shí)需要獲取包的metadata中的rotate參數(shù),計(jì)算出旋轉(zhuǎn)角度,按照旋轉(zhuǎn)角度渲染視頻才能顯示正常的畫面。
一、如何實(shí)現(xiàn)
sdl支持旋轉(zhuǎn)渲染使用SDL_RenderCopyEx設(shè)置旋轉(zhuǎn)角度即可旋轉(zhuǎn)畫面,但是直接設(shè)置之后顯示的畫面位置是異常的,尤其時(shí)旋轉(zhuǎn)非直角角度后畫面大小會(huì)大一些,所以需要對(duì)旋轉(zhuǎn)后的畫面的位置以及大小進(jìn)行一些處理。
1、計(jì)算邊框大小
計(jì)算旋轉(zhuǎn)后的邊框大小。知道視頻畫面寬高和旋轉(zhuǎn)角度,根據(jù)三角函數(shù)即可計(jì)算出邊框大小,這里就沒必要具體說(shuō)明了。
邊框?qū)?視頻高∗sinθ+視頻寬∗cosθ
邊框高=視頻高∗cosθ+視頻寬∗sinθ
示例代碼:
//srcRect為視頻區(qū)域,angle為旋轉(zhuǎn)角度 const double PI = 3.1415926535897935384626; //角度轉(zhuǎn)弧度,用于三角函數(shù)計(jì)算。 double theta = PI / 180.0 * angle; //計(jì)算旋轉(zhuǎn)后的邊框大小,+0.5四舍五入 int width = srcRect->h * fabs(sin(theta) )+ srcRect->w * fabs(cos(theta)) + 0.5; int height = srcRect->h * fabs(cos(theta)) + srcRect->w * fabs(sin(theta)) + 0.5;
2、計(jì)算縮放大小
邊框?qū)?邊框?qū)?lowast;縮放比
邊框高=邊框高∗縮放比
代碼示例:
//邊框的寬高比 double srcBorderRatio = (double)width / height; //目標(biāo)區(qū)域的寬高比 double dstRatio = (double)dstRect->w / dstRect->h; //計(jì)算邊框縮放到目標(biāo)區(qū)域的大小 int zoomWidth; int zoomHeight; if (srcBorderRatio > dstRatio) { zoomWidth = dstRect->w; zoomHeight = dstRect->w / srcBorderRatio; } else { zoomWidth = dstRect->h * srcBorderRatio; zoomHeight = dstRect->h; }
3、逆運(yùn)算視頻寬高
視頻高=邊框?qū)?(sinθ+視頻寬高比∗cosθ)
視頻寬=視頻高∗視頻寬高比
代碼示例:
//視頻的寬高比 double srcRatio = (double)srcRect->w / srcRect->h; //通過(guò)縮放后的邊框計(jì)算還原的圖像大小 targetRect.h = (double)zoomWidth / (fabs(sin(theta) )+ srcRatio * fabs(cos(theta))); targetRect.w = targetRect.h * srcRatio; targetRect.x = (dstRect->w- targetRect.w ) / 2; targetRect.y = (dstRect->h- targetRect.h ) / 2;
二、完整代碼
/// <summary> /// 計(jì)算旋轉(zhuǎn)的矩形大小 /// </summary> /// <param name="src">原圖像區(qū)域</param> /// <param name="dst">目標(biāo)區(qū)域</param> /// <param name="angle">旋轉(zhuǎn)角度</param> /// <returns></returns> static SDL_Rect getRotateRect(SDL_Rect *srcRect, SDL_Rect* dstRect,double angle) { SDL_Rect targetRect; const double PI = 3.1415926535897935384626; double theta = PI / 180.0 * angle; //計(jì)算旋轉(zhuǎn)后的邊框大小 int width = srcRect->h * fabs(sin(theta) )+ srcRect->w * fabs(cos(theta)) + 0.5; int height = srcRect->h * fabs(cos(theta)) + srcRect->w * fabs(sin(theta)) + 0.5; double srcRatio = (double)srcRect->w / srcRect->h; double srcBorderRatio = (double)width / height; double dstRatio = (double)dstRect->w / dstRect->h; //計(jì)算邊框縮放到目標(biāo)區(qū)域的大小 int zoomWidth; int zoomHeight; if (srcBorderRatio > dstRatio) { zoomWidth = dstRect->w; zoomHeight = dstRect->w / srcBorderRatio; } else { zoomWidth = dstRect->h * srcBorderRatio; zoomHeight = dstRect->h; } //通過(guò)縮放后的邊框計(jì)算還原的圖像大小 targetRect.h = (double)zoomWidth / (fabs(sin(theta) )+ srcRatio * fabs(cos(theta))); targetRect.w = targetRect.h * srcRatio; targetRect.x = (dstRect->w- targetRect.w ) / 2; targetRect.y = (dstRect->h- targetRect.h ) / 2; return targetRect; }
三、使用示例
只展示渲染部分,初始化及獲取視頻略。
//窗口區(qū)域 sdlRect.x = 0; sdlRect.y = 0; sdlRect.w = video->screen_w; sdlRect.h = video->screen_h; //視頻區(qū)域 sdlRect2.x = 0; sdlRect2.y = 0; sdlRect2.w = video->decoder.codecContext->width; sdlRect2.h = video->decoder.codecContext->height; //渲染到sdl窗口 SDL_RenderClear(video->sdlRenderer); SDL_UpdateYUVTexture(video->sdlTexture, &sdlRect2, dst_data[0], dst_linesize[0], dst_data[1], dst_linesize[1], dst_data[2], dst_linesize[2]); if (video->angle == 0) SDL_RenderCopy(video->sdlRenderer, video->sdlTexture, NULL, &sdlRect); else //當(dāng)旋轉(zhuǎn)角度不為0時(shí)使用SDL_RenderCopyEx渲染 { SDL_Rect sdlRect3; //計(jì)算旋轉(zhuǎn)后的目標(biāo)區(qū)域 sdlRect3= getRotateRect(&sdlRect2,&sdlRect,video->angle); SDL_RenderCopyEx(video->sdlRenderer, video->sdlTexture, NULL , &sdlRect3, video->angle, 0, SDL_FLIP_NONE); } SDL_RenderPresent(video->sdlRenderer);
效果預(yù)覽:
1、mp4 metadata-rotate為270,未處理旋轉(zhuǎn)的情況:
2、旋轉(zhuǎn)270度后
3、自定義旋轉(zhuǎn)角度
總結(jié)
以上就是今天要講的內(nèi)容,做音視頻開發(fā)過(guò)程中還是比較少遇到需要旋轉(zhuǎn)視頻的場(chǎng)景的,筆者也是測(cè)試播放器的時(shí)候,無(wú)意中發(fā)現(xiàn)自己手機(jī)的視頻播放時(shí)畫面倒轉(zhuǎn)了,經(jīng)過(guò)一番探究才了解到播放視頻時(shí)需要處理rotate信息,于是實(shí)現(xiàn)了sdl渲染帶旋轉(zhuǎn)參數(shù)的視頻,順帶也支持任意角度旋轉(zhuǎn)。
到此這篇關(guān)于C++ sdl實(shí)現(xiàn)渲染旋轉(zhuǎn)視頻的方法分享的文章就介紹到這了,更多相關(guān)sdl渲染旋轉(zhuǎn)視頻內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c++類的隱式轉(zhuǎn)換與強(qiáng)制轉(zhuǎn)換重載詳解
轉(zhuǎn)換函數(shù)的名稱是類型轉(zhuǎn)換的目標(biāo)類型,因此,不必再為它指定返回值類型;轉(zhuǎn)換函數(shù)是被用于本類型的數(shù)值或變量轉(zhuǎn)換為其他的類型,也不必帶參數(shù)2013-09-09在vs2010中,輸出當(dāng)前文件路徑與源文件當(dāng)前行號(hào)的解決方法
本篇文章是對(duì)在vs2010中,輸出當(dāng)前文件路徑與源文件當(dāng)前行號(hào)的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05解析OpenSSL1.1.1?centos7安裝編譯aes的c++調(diào)用
這篇文章主要介紹了OpenSSL1.1.1?centos7安裝編譯aes的c++調(diào)用,實(shí)現(xiàn)方法也很簡(jiǎn)單,主要是在該文檔內(nèi)加入openssl的lib路徑,感興趣的朋友跟隨小編一起看看吧2022-03-03一篇文章帶你了解C語(yǔ)言的選擇結(jié)構(gòu)
這篇文章主要為大家介紹了C語(yǔ)言的選擇結(jié)構(gòu),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-01-01