視頻編解碼學習三 播放yuv格式視頻

??今天的主題是播放yuv格式視頻。
在上兩篇博客里面介紹過了如何將視頻解碼為單獨的視頻和音頻,但是如果播放這些格式的文件呢,安卓原生是沒有這些控件來直播播放yuv格式視頻的,必須通過借助其他方式來播放,今天就介紹SDL2來解碼播放yuv文件。

SDL

??什么是SDL?SDL(Simple DirectMedia Layer)是一套開放源代碼的跨平臺多媒體開發庫,專門用來開發多媒體,游戲等。詳細想了解的可以去SDL官方文檔查看

下面是FFmpeg官方給出的播放流程


image.png

根據上面的流程,在得到yuv像素數據的時候就可以渲染了

采用SDL播放yuv文件播放流程:
?? 第一步:初始化SDL多媒體框架->SDL_Init
??第二步:初始化SDL窗口
??第三步:創建渲染器->渲染窗口(OpenGL ES)
??第四步:設置紋理數據->播放YUV視頻
??第五步:將紋理數據拷貝到渲染器
??第六步:顯示幀畫面
??第七步:退出SDL釋放內存

源碼

#include <jni.h>
#include <android/log.h>

#define LOG_I(...) __android_log_print(ANDROID_LOG_ERROR , "main", __VA_ARGS__)

#include "SDL.h"
#include "SDL_log.h"
#include "SDL_main.h"

////avcodec:編解碼(最重要的庫)
//#include "libavcodec/avcodec.h"
////avformat:封裝格式處理
//#include "libavformat/avformat.h"
////avutil:工具庫(大部分庫都需要這個庫的支持)
//#include "libavutil/imgutils.h"
////swscale:視頻像素數據格式轉換
//#include "libswscale/swscale.h"
////導入音頻采樣數據格式轉換庫
//#include "libswresample/swresample.h"

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
}
int main(int argc, char *argv[]) {
    //第一步:初始化SDL多媒體框架->SDL_Init
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) {
        LOG_I("SDL_Init failed %s", SDL_GetError());
        return 0;
    }
    LOG_I("SDL_Init Success!");

    //第二步:初始化SDL窗口
    //參數一:窗口名稱->要求必需是UTF-8編碼
    //參數二:窗口在屏幕上面X坐標
    //參數三:窗口在屏幕上面Y坐標
    //參數四:窗口在屏幕上面寬
    int width = 640;
    //參數五:窗口在屏幕上面高
    int height = 352;
    //參數六:窗口狀態(打開的狀態:SDL_WINDOW_OPENGL)
    SDL_Window* sdl_window = SDL_CreateWindow("SDL播放器",
                                              SDL_WINDOWPOS_CENTERED,
                                              SDL_WINDOWPOS_CENTERED,
                                              width ,
                                              height,
                                              SDL_WINDOW_OPENGL);
    if (sdl_window == NULL){
        LOG_I("窗口創建失敗");
        return 0;
    }

    //第三步:創建渲染器->渲染窗口(OpenGL ES)
    //最新一期VIP課程
    //參數一:渲染目標窗口
    //參數二:從哪里開始渲染(-1:默認從第一個為止開始)
    //參數三:渲染類型
    //SDL_RENDERER_SOFTWARE:軟件渲染
    //...
    SDL_Renderer* sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);

    //第四步:創建紋理
    //參數一:紋理目標渲染器
    //參數二:渲染格式
    //參數三:繪制方式(SDL_TEXTUREACCESS_STREAMING:頻繁繪制)
    //參數四:紋理寬
    //參數五:紋理高
    SDL_Texture * sdl_texture = SDL_CreateTexture(sdl_renderer,
                                                  SDL_PIXELFORMAT_IYUV,
                                                  SDL_TEXTUREACCESS_STREAMING,
                                                  width,
                                                  height);

    //第五步:設置紋理數據->播放YUV視頻
    //著色器語言(著色器)、渲染器、紋理等等...
    //第一點:打開YUV文件(手機:)
    FILE* yuv_file = fopen("/storage/emulated/0/DreamTestFile/Test.yuv","rb+");
    if (yuv_file == NULL){
        LOG_I("文件打開失敗");
        return 0;
    }

    //第二點:循環讀取YUV視頻像素數據格式每一幀畫面->渲染->設置紋理數據
    //定義緩沖區(內存空間開辟多大?)
    //Y:U:V = 4 : 1 : 1
    //假設:Y = 1.0  U = 0.25  V = 0.25
    //寬度:Y + U + V = 1.5
    //換算:Y + U + V = width * height * 1.5
    char buffer_pix[width * height * 3 / 2];

    //定義渲染器區域
    SDL_Rect sdl_rect;
    while (true){
        //一行一行的讀取
        fread(buffer_pix, 1, width * height * 3 / 2, yuv_file);
        //判定是否讀取完畢
        if (feof(yuv_file)){
            break;
        }

        //設置紋理數據
        //參數一:目標紋理對象
        //參數二:渲染區域(NULL:表示默認屏幕窗口寬高)
        //參數三:視頻像素數據
        //參數四:幀畫面寬
        SDL_UpdateTexture(sdl_texture, NULL, buffer_pix, width);

        //第六步:將紋理數據拷貝到渲染器
        sdl_rect.x = 0;
        sdl_rect.y = 0;
        sdl_rect.w = width;
        sdl_rect.h = height;

        //先清空
        SDL_RenderClear(sdl_renderer);
        //再渲染
        SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,&sdl_rect);

        //第七步:顯示幀畫面
        SDL_RenderPresent(sdl_renderer);

        //第八步:延時渲染(沒渲染一幀間隔時間)
        SDL_Delay(20);
    }


    //第九步:是否內存
    fclose(yuv_file);

    SDL_DestroyTexture(sdl_texture);

    SDL_DestroyRenderer(sdl_renderer);


    //第十步:推出SDL程序
    SDL_Quit();
    return 0;
}

上面的源碼只是演示如何播放yuv格式視頻,當然在實際項目中還需要根據具體業務加入具體業務邏輯,在播放網絡流的情況下還需要處理音頻和視頻間的同步和時間戳問題。這里推薦一個SDL和FFmpeg的國外教程,很實用的一個教程。

下載

https://github.com/samychen/SDL_FFmpeg_Tutorial

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,749評論 0 3
  • ??最近研究直播,一路下來遇到了很多問題,但最終經過半年的學習,在音視頻這塊已經有了進一步的理解,感謝我的朋友們給...
    samychen閱讀 5,865評論 0 5
  • 隨著互聯網技術的飛速發展,移動端播放視頻的需求如日中天,由此也催生了一批開源/閉源的播放器,但是無論這個播放器功能...
    金山視頻云閱讀 46,461評論 28 170
  • 前言 前面介紹了設備搜索、獲取設備能力信息,在此基礎上,本篇博客介紹如何播放音視頻(ONVIF協議 + FFmpe...
    ORCLee閱讀 3,631評論 0 0
  • 今夜 又下起了小雨 像無語的你 把無從說起的心事 悄聲的灑落 淅瀝的小雨 訴說著落寞的荒涼 那癡纏的風 帶著飄蕩的...
    凌空chL5658閱讀 463評論 7 30