ffconv/examples/ffPlayer.cpp

99 lines
3.2 KiB
C++

#include "ffcpp/Player.h"
#include <memory>
#include <SDL.h>
#include <SDL_thread.h>
#include <iostream>
#include <future>
namespace ff = ffcpp;
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
class SDLWindow: public ff::IVideoSink {
private:
template<typename T> using SDLUniquePtr = std::unique_ptr<T, void(*)(T*)>;
using SDLWindowPtr = SDLUniquePtr<SDL_Window>;
using SDLRendererPtr = SDLUniquePtr<SDL_Renderer>;
using SDLTexturePtr = SDLUniquePtr<SDL_Texture>;
private:
SDLWindowPtr _wnd;
SDLRendererPtr _renderer;
SDLTexturePtr _texture;
std::packaged_task<void()> _renderTask;
public:
SDLWindow(): _wnd(nullptr, SDL_DestroyWindow), _renderer(nullptr, SDL_DestroyRenderer), _texture(nullptr, SDL_DestroyTexture) {
int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
if(res < 0) throw std::runtime_error("Error initializing SDL");
_wnd.reset(SDL_CreateWindow("ffPlayer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL));
if(!_wnd) throw std::runtime_error("Error creating SDL window");
_renderer.reset(SDL_CreateRenderer(_wnd.get(), -1, 0));
if(!_renderer) throw std::runtime_error("Error creating SDL renderer");
_texture.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, WINDOW_WIDTH, WINDOW_HEIGHT));
if(!_texture) throw std::runtime_error("Error creating SDL texture");
}
void handleEvents() {
SDL_Event event;
while(true) {
SDL_WaitEvent(&event);
switch(event.type) {
case SDL_QUIT:
return;
case SDL_USEREVENT: {
_renderTask();
break;
}
}
}
}
public:
virtual AVPixelFormat getPixelFormat() const noexcept override {
return AV_PIX_FMT_YUV420P;
}
virtual void drawFrame(void* pixelsData, int pitch) override {
std::cout << "drawing frame" << std::endl;
SDL_UpdateTexture(_texture.get(), nullptr, pixelsData, pitch);
SDL_RenderClear(_renderer.get());
SDL_RenderCopy(_renderer.get(), _texture.get(), nullptr, nullptr);
SDL_RenderPresent(_renderer.get());
}
virtual void drawPlanarYUVFrame(const void *yPlane, const void *uPlane, const void *vPlane, int yPitch, int uPitch, int vPitch) override {
_renderTask = std::packaged_task<void()>([=]{
SDL_UpdateYUVTexture(_texture.get(), nullptr, (const uint8_t*)yPlane, yPitch, (const uint8_t*)uPlane, uPitch, (const uint8_t*)vPlane, vPitch);
SDL_RenderClear(_renderer.get());
SDL_RenderCopy(_renderer.get(), _texture.get(), nullptr, nullptr);
SDL_RenderPresent(_renderer.get());
});
auto future = _renderTask.get_future();
SDL_Event event;
event.type = SDL_USEREVENT;
int res = SDL_PushEvent(&event);
future.get();
}
};
int main(int argc, char** argv) {
auto wnd = std::make_shared<SDLWindow>();
ff::Player player(wnd);
player.setMedia(argv[1]);
player.setVideoSize(WINDOW_WIDTH, WINDOW_HEIGHT);
player.play();
wnd->handleEvents();
return 0;
}