YuvPlayer works well
[yuv-player.git] / yuvPlayer.cpp
diff --git a/yuvPlayer.cpp b/yuvPlayer.cpp
new file mode 100644 (file)
index 0000000..322975e
--- /dev/null
@@ -0,0 +1,108 @@
+#include<iostream>
+#include<fstream>
+#include "SDL2/SDL.h"
+
+using namespace std;
+
+/*
+ * Convert MP4 to YUV
+ * ffmpeg -i big_buck_bunny_720p_10mb.mp4 -c:v rawvideo -pix_fmt yuv420p out.yuv
+ *
+ * Play YUV with ffplay
+ * ffplay -f rawvideo -pixel_format yuv420p -video_size 1280x720 -i ./out.yuv
+ *
+ */
+
+class YuvPlayer 
+{
+public:
+    YuvPlayer(int width, int height);
+    void play(string fname);
+    ~YuvPlayer();
+
+private:
+    bool readFrame(ifstream& in, uint8_t *raw, size_t size);
+    void updateRenderer(uint8_t *raw);
+    string file;
+    int width = 1280;
+    int height = 720;
+    SDL_Window *window;
+    SDL_Renderer *renderer;
+    SDL_Texture *texture;
+};
+
+YuvPlayer::YuvPlayer(int w, int h)
+: width(w)
+, height(h)
+{
+    SDL_Init(SDL_INIT_VIDEO);
+    window = SDL_CreateWindow("YUV Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
+    if (window == nullptr){
+        cout << "create error: " << SDL_GetError() << endl;
+    }
+    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
+}
+
+YuvPlayer::~YuvPlayer()
+{
+    SDL_DestroyWindow(window);
+    SDL_Quit();
+}
+
+void YuvPlayer::play(string file)
+{
+    size_t frame_size = width * height * 3 / 2;
+    uint8_t *raw = (uint8_t *) malloc(sizeof(uint8_t) * frame_size);
+    ifstream in (file, ios::binary);
+    if (!in.is_open()) {
+        cout << "failed to open " << file << endl;
+    }
+
+    SDL_Event event;
+    bool quit = false;
+    while(!quit) {
+        SDL_WaitEvent(&event);
+        switch(event.type){
+            case SDL_QUIT:
+                quit = true;
+                break;
+            case SDL_KEYDOWN:
+                switch(event.key.keysym.sym){
+                    case SDLK_q:
+                        quit = true;
+                        break;
+                    case SDLK_RIGHT:
+                        readFrame(in, raw, frame_size);
+                        updateRenderer(raw);
+                        break;
+                    default:
+                        break;
+                }
+            default:
+                break;
+        }
+    }
+    free(raw);
+}
+
+bool YuvPlayer::readFrame(ifstream& in, uint8_t *raw, size_t size)
+{
+    in.read(reinterpret_cast<char *>(raw), size);
+    return true;
+}
+
+void YuvPlayer::updateRenderer(uint8_t *raw)
+{    
+    SDL_UpdateTexture(texture, nullptr, raw, width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV));
+    SDL_RenderClear(renderer);
+    SDL_RenderCopy(renderer, texture, nullptr, nullptr);
+    SDL_RenderPresent(renderer);
+}
+
+int main()
+{
+    string fname = "out.yuv";
+    YuvPlayer player(1280, 720);
+    player.play(fname);
+}