X-Git-Url: http://47.100.26.94:8080/?a=blobdiff_plain;f=yuvPlayer.cpp;h=fb8c1a995208c418c1c7d9ab7d03dc21e9c2d9f5;hb=refs%2Fheads%2Fmaster;hp=322975e798a3dd109074c33748d56a5aede6440f;hpb=7de7c3da29277838e63b63ffd2512b4014b90fa7;p=yuv-player.git diff --git a/yuvPlayer.cpp b/yuvPlayer.cpp index 322975e..fb8c1a9 100644 --- a/yuvPlayer.cpp +++ b/yuvPlayer.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "SDL2/SDL.h" using namespace std; @@ -11,13 +14,20 @@ using namespace std; * Play YUV with ffplay * ffplay -f rawvideo -pixel_format yuv420p -video_size 1280x720 -i ./out.yuv * + * Usage: + * 1. press 'P' to pause or play as the given framerate + * 2. press 'q' to quit + * 3. press RIGHT to next frame, LEFT to previous frame + * 4. color space transform */ class YuvPlayer { public: - YuvPlayer(int width, int height); - void play(string fname); + YuvPlayer(int width, int height, const string& title = "YUV Player"); + void play(string fname, int fps = -1); + void toggleGrid(); + void toggleYumaOnly(); ~YuvPlayer(); private: @@ -29,14 +39,33 @@ private: SDL_Window *window; SDL_Renderer *renderer; SDL_Texture *texture; + unsigned int frameCnt = 0; + string title; + ifstream::pos_type last_pos; + bool isShowingGrid = false; + bool isLumOnly = false; + uint8_t *raw; }; -YuvPlayer::YuvPlayer(int w, int h) + +class ImageOperation { +public: + ImageOperation(uint8_t *r, int width, int height); + + +private: + int width; + int height; + uint8_t *raw; +}; + +YuvPlayer::YuvPlayer(int w, int h, const string& t) : width(w) , height(h) +, title(t) { SDL_Init(SDL_INIT_VIDEO); - window = SDL_CreateWindow("YUV Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN); + window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN); if (window == nullptr){ cout << "create error: " << SDL_GetError() << endl; } @@ -46,23 +75,49 @@ YuvPlayer::YuvPlayer(int w, int h) YuvPlayer::~YuvPlayer() { + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } -void YuvPlayer::play(string file) +// https://wiki.videolan.org/YUV/, YCrCb +// I420, YUV420p, YYYY YYYY UU VV +static void lumaOnly(uint8_t *raw, int w, int h) +{ + memset(raw + w * h, 128, w * h / 2); // UV 128 + //memset(raw + w * h, 0, w * h / 2); // UV 128 + //memset(raw + w * h, 0, w * h / 2); // UV 0, G only + //memset(raw + w * h, 255, w * h / 2); // UV 0, R only + //memset(raw + w * h, 128, w * h / 4); // U 128 + //for (int i = 0; i < w * h; i++){ + // raw[i] = raw[i] / 2; // Y to 1/2 + //} +} + +void YuvPlayer::play(string file, int fps) { size_t frame_size = width * height * 3 / 2; - uint8_t *raw = (uint8_t *) malloc(sizeof(uint8_t) * frame_size); + 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; + bool isPlaying = true; + int interval = 1000 / fps; + while(!quit) { - SDL_WaitEvent(&event); + interval = isPlaying ? 1000 / fps : -1; + SDL_WaitEventTimeout(&event, interval); + if(fps > 0 && isPlaying){ + if(readFrame(in, raw, frame_size)){ + updateRenderer(raw); + } + } switch(event.type){ case SDL_QUIT: quit = true; @@ -73,9 +128,26 @@ void YuvPlayer::play(string file) quit = true; break; case SDLK_RIGHT: - readFrame(in, raw, frame_size); - updateRenderer(raw); + if(readFrame(in, raw, frame_size)){ + updateRenderer(raw); + } + break; + case SDLK_LEFT: + frameCnt = frameCnt >= 2 ? frameCnt - 2 : 0; + in.seekg(frameCnt * frame_size); + if(readFrame(in, raw, frame_size)){ + updateRenderer(raw); + } + break; + case SDLK_p: + isPlaying = !isPlaying; + break; + case SDLK_g: + toggleGrid(); + break; + case SDLK_y: + toggleYumaOnly(); default: break; } @@ -85,24 +157,67 @@ void YuvPlayer::play(string file) } free(raw); } +void YuvPlayer::toggleYumaOnly() +{ + isLumOnly = !isLumOnly; + updateRenderer(this->raw); +} + +void YuvPlayer::toggleGrid() +{ + isShowingGrid = !isShowingGrid; + updateRenderer(raw); +} + bool YuvPlayer::readFrame(ifstream& in, uint8_t *raw, size_t size) { - in.read(reinterpret_cast(raw), size); - return true; + last_pos = in.tellg(); + bool ret = (bool) in.read(reinterpret_cast(raw), size); + if (ret){ + frameCnt++; + stringstream ss; + ss << this->title << " [" << setw(4) << to_string(frameCnt) << "]"; + SDL_SetWindowTitle(window, ss.str().c_str()); + }else { + cout << "read error" << endl; + } + return ret; } void YuvPlayer::updateRenderer(uint8_t *raw) { + if (isLumOnly){ + lumaOnly(raw, width, height); + } SDL_UpdateTexture(texture, nullptr, raw, width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV)); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, nullptr, nullptr); + + if(isShowingGrid){ + SDL_SetRenderDrawColor( renderer, 0x00, 0x00, 0xFF, 0xFF ); + //SDL_RenderDrawLine( renderer, 0, height / 2, width, height / 2 ); + SDL_RenderDrawLine( renderer, 0, height / 3, width, height / 3 ); + SDL_RenderDrawLine( renderer, 0, height * 2 / 3, width, height * 2 / 3 ); + + SDL_RenderDrawLine( renderer, width / 3, 0, width / 3, height ); + SDL_RenderDrawLine( renderer, width * 2 / 3, 0, width * 2 / 3, height ); + + } + SDL_RenderPresent(renderer); } -int main() +int main(int argc, char* argv[]) { - string fname = "out.yuv"; +// string fname(argv[1] ? argv[1] : "out.yuv"); +// size_t width = atoi(argv[2] ? argv[2] : "1280"); +// size_t height = atoi(argv[3] ? argv[3] : "720"); +// +// int fps = atoi(argv[4] ? argv[4] : "20"); +// cout << fname << "\n" << width << "\n" << height << "\n" << fps << "\n" << endl; +// YuvPlayer player(1280, 720); - player.play(fname); + player.play("out.yuv", 25); + //player.play(fname); }