diff --git a/examples/ffPlayer.cpp b/examples/ffPlayer.cpp index ec1f70f..29604af 100644 --- a/examples/ffPlayer.cpp +++ b/examples/ffPlayer.cpp @@ -1,16 +1,79 @@ #include "ffcpp/Player.h" #include +#include +#include +#include + +#include +#include namespace ff = ffcpp; -class SDLWindow: public ff::IVideoSink { +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +class SDLWindow: public ff::IVideoSink { +private: + template using SDLUniquePtr = std::unique_ptr; + using SDLWindowPtr = SDLUniquePtr; + using SDLRendererPtr = SDLUniquePtr; + using SDLTexturePtr = SDLUniquePtr; + +private: + SDLWindowPtr _wnd; + SDLRendererPtr _renderer; + SDLTexturePtr _texture; + +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_YV12, SDL_TEXTUREACCESS_STREAMING, WINDOW_WIDTH, WINDOW_HEIGHT)); + if(!_texture) throw std::runtime_error("Error creating SDL texture"); + } + +public: + virtual AVPixelFormat getPixelFormat() const noexcept override { + return AV_PIX_FMT_YUV420P; + } + + virtual int getWidth() const noexcept override { + return WINDOW_WIDTH; + } + + virtual int getHeight() const noexcept override { + return WINDOW_HEIGHT; + } + + 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 { + 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()); + //std::this_thread::sleep_for(std::chrono::milliseconds(40)); + } }; int main(int argc, char** argv) { auto wnd = std::make_shared(); ff::Player player(wnd); player.setMedia(argv[1]); + player.play(); return 0; } \ No newline at end of file diff --git a/include/ffcpp/Player.h b/include/ffcpp/Player.h index 07e6514..2a3348b 100644 --- a/include/ffcpp/Player.h +++ b/include/ffcpp/Player.h @@ -7,7 +7,12 @@ namespace ffcpp { struct IVideoSink { - + virtual AVPixelFormat getPixelFormat() const noexcept = 0; + virtual int getWidth() const noexcept = 0; + virtual int getHeight() const noexcept = 0; + virtual void drawFrame(void* pixelsData, int pitch) = 0; + virtual void drawPlanarYUVFrame(const void *yPlane, const void *uPlane, const void *vPlane, int yPitch, + int uPitch, int vPitch) = 0; }; class Player { diff --git a/src/Player.cpp b/src/Player.cpp index c6b28c6..6c53bb2 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -1,5 +1,6 @@ #include "ffcpp/Player.h" #include "ffcpp/Stream.h" +#include "ffcpp/Scaler.h" namespace ffcpp { @@ -17,15 +18,26 @@ namespace ffcpp { _vStream = _curMedia->videoStream(); _aStream = _curMedia->audioStream(); - - auto vDecoder = _vStream->codec(); - auto aDecoder = _aStream->codec(); } void Player::play() { if(!_curMedia) return; + auto vDecoder = _vStream->codec(); + auto aDecoder = _aStream->codec(); + Scaler scaler(vDecoder->width(), vDecoder->height(), vDecoder->pixelFormat(), + _vSink->getWidth(), _vSink->getHeight(), _vSink->getPixelFormat()); + while(auto packet = _curMedia->readPacket()) { + AVMediaType packetType = _curMedia->packetType(packet); + if(packetType == AVMEDIA_TYPE_VIDEO) { + auto frame = vDecoder->decode(packet); + frame = scaler.scale(frame); + AVFrame* f = frame; + //_vSink->drawFrame(f->data, f->linesize[0]); + _vSink->drawPlanarYUVFrame(f->data[0], f->data[1], f->data[2], f->linesize[0], f->linesize[1], f->linesize[2]); + } + } } } \ No newline at end of file