1. 程式人生 > 其它 >音視訊之播放YUV資料(十二)

音視訊之播放YUV資料(十二)

使用SDL顯示YUV資料

巨集定義

extern "C" {
#include <libavutil/imgutils.h>
}

#define RET(judge, func) \
    if (judge) { \
        qDebug() << #func << "error" << SDL_GetError(); \
        return; \
    }

static const std::map<AVPixelFormat, SDL_PixelFormatEnum>
PIXEL_FORMAT_MAP 
= { {AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV}, {AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2}, {AV_PIX_FMT_NONE, SDL_PIXELFORMAT_UNKNOWN} };

變數定義

 SDL_Window *_window = nullptr;
 SDL_Renderer *_renderer = nullptr;
 SDL_Texture *_texture = nullptr;
 QFile _file;
 int _timerId = 0;
 State _state 
= Stopped; Yuv _yuv; bool _playing;

建立視窗

// 建立視窗
_window = SDL_CreateWindowFrom((void *)winId());
RET(!_window, SDL_CreateWindow);

建立渲染上下文

// 建立渲染上下文
    _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!_renderer) {
        _renderer = SDL_CreateRenderer(_window, -1
, 0); RET(!_renderer, SDL_CreateRenderer); }

建立紋理

// 建立紋理
    _texture = SDL_CreateTexture(_renderer,
                                 PIXEL_FORMAT_MAP.find(yuv.pixelFormat)->second,
                                 SDL_TEXTUREACCESS_STREAMING,
                                 yuv.width,
                                 yuv.height);
    RET(!_texture, SDL_CreateTextureFromSurface);

開啟檔案

 // 開啟檔案
    _file.setFileName(yuv.filename);
    if (!_file.open(QFile::ReadOnly)) {
        qDebug() << "file open error" << yuv.filename;
    }

渲染

// 圖片大小
    int imgSize = av_image_get_buffer_size(_yuv.pixelFormat,
                                           _yuv.width,
                                           _yuv.height,
                                           1);

    char data[imgSize];
    if (_file.read(data, imgSize) > 0) {
        // 將YUV的畫素資料填充到texture
        RET(SDL_UpdateTexture(_texture, nullptr, data, _yuv.width), SDL_UpdateTexture);

        // 設定繪製顏色 (畫筆顏色)
        RET(SDL_SetRenderDrawColor(_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE), SDL_SetRenderDrawColor);

        //用繪製顏色 (畫筆顏色) 清除渲染目標
        RET(SDL_RenderClear(_renderer), SDL_RenderClear);

        // 拷貝紋理資料到渲染目標(預設是window)
        RET(SDL_RenderCopy(_renderer, _texture, nullptr, nullptr), SDL_RenderCopy);

        // 更新所有的渲染操作到螢幕上
        SDL_RenderPresent(_renderer);
    } else {
        // 檔案資料已經讀取
        killTimer(_timerId);
    }

對應的播放、暫停、播放狀態

void YuvPlayer::play() {
    _timerId = startTimer(1000 / _yuv.fps);
    _state = YuvPlayer::Playing;
}

void YuvPlayer::pause() {
    if (_timerId) {
        killTimer(_timerId);
    }
    _state = YuvPlayer::Paused;
}

void YuvPlayer::stop() {
    if (_timerId) {
        killTimer(_timerId);
    }
    _state = YuvPlayer::Stopped;
}

bool YuvPlayer::isPlaying() {
    return _state == YuvPlayer::Playing;
}

YuvPlayer::State YuvPlayer::getstate() {
    return _state;
}

釋放資源

YuvPlayer::~YuvPlayer() {
    _file.close();
    SDL_DestroyTexture(_texture);
    SDL_DestroyRenderer(_renderer);
    SDL_DestroyWindow(_window);
}