12 * ffmpeg -i big_buck_bunny_720p_10mb.mp4 -c:v rawvideo -pix_fmt yuv420p out.yuv
14 * Play YUV with ffplay
15 * ffplay -f rawvideo -pixel_format yuv420p -video_size 1280x720 -i ./out.yuv
18 * 1. press 'P' to pause or play as the given framerate
19 * 2. press 'q' to quit
20 * 3. press RIGHT to next frame, LEFT to previous frame
21 * 4. color space transform
27 YuvPlayer(int width, int height, const string& title = "YUV Player");
28 void play(string fname, int fps = -1);
30 void toggleYumaOnly();
34 bool readFrame(ifstream& in, uint8_t *raw, size_t size);
35 void updateRenderer(uint8_t *raw);
40 SDL_Renderer *renderer;
42 unsigned int frameCnt = 0;
44 ifstream::pos_type last_pos;
45 bool isShowingGrid = false;
46 bool isLumOnly = false;
51 class ImageOperation {
53 ImageOperation(uint8_t *r, int width, int height);
62 YuvPlayer::YuvPlayer(int w, int h, const string& t)
67 SDL_Init(SDL_INIT_VIDEO);
68 window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
69 if (window == nullptr){
70 cout << "create error: " << SDL_GetError() << endl;
72 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
73 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
76 YuvPlayer::~YuvPlayer()
78 SDL_DestroyTexture(texture);
79 SDL_DestroyRenderer(renderer);
80 SDL_DestroyWindow(window);
84 // https://wiki.videolan.org/YUV/, YCrCb
85 // I420, YUV420p, YYYY YYYY UU VV
86 static void lumaOnly(uint8_t *raw, int w, int h)
88 memset(raw + w * h, 128, w * h / 2); // UV 128
89 //memset(raw + w * h, 0, w * h / 2); // UV 128
90 //memset(raw + w * h, 0, w * h / 2); // UV 0, G only
91 //memset(raw + w * h, 255, w * h / 2); // UV 0, R only
92 //memset(raw + w * h, 128, w * h / 4); // U 128
93 //for (int i = 0; i < w * h; i++){
94 // raw[i] = raw[i] / 2; // Y to 1/2
98 void YuvPlayer::play(string file, int fps)
100 size_t frame_size = width * height * 3 / 2;
101 raw = (uint8_t *) malloc(sizeof(uint8_t) * frame_size);
102 ifstream in (file, ios::binary);
104 cout << "failed to open " << file << endl;
110 bool isPlaying = true;
111 int interval = 1000 / fps;
114 interval = isPlaying ? 1000 / fps : -1;
115 SDL_WaitEventTimeout(&event, interval);
116 if(fps > 0 && isPlaying){
117 if(readFrame(in, raw, frame_size)){
126 switch(event.key.keysym.sym){
131 if(readFrame(in, raw, frame_size)){
136 frameCnt = frameCnt >= 2 ? frameCnt - 2 : 0;
137 in.seekg(frameCnt * frame_size);
138 if(readFrame(in, raw, frame_size)){
144 isPlaying = !isPlaying;
160 void YuvPlayer::toggleYumaOnly()
162 isLumOnly = !isLumOnly;
163 updateRenderer(this->raw);
166 void YuvPlayer::toggleGrid()
168 isShowingGrid = !isShowingGrid;
173 bool YuvPlayer::readFrame(ifstream& in, uint8_t *raw, size_t size)
175 last_pos = in.tellg();
176 bool ret = (bool) in.read(reinterpret_cast<char *>(raw), size);
180 ss << this->title << " [" << setw(4) << to_string(frameCnt) << "]";
181 SDL_SetWindowTitle(window, ss.str().c_str());
183 cout << "read error" << endl;
188 void YuvPlayer::updateRenderer(uint8_t *raw)
191 lumaOnly(raw, width, height);
193 SDL_UpdateTexture(texture, nullptr, raw, width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV));
194 SDL_RenderClear(renderer);
195 SDL_RenderCopy(renderer, texture, nullptr, nullptr);
198 SDL_SetRenderDrawColor( renderer, 0x00, 0x00, 0xFF, 0xFF );
199 //SDL_RenderDrawLine( renderer, 0, height / 2, width, height / 2 );
200 SDL_RenderDrawLine( renderer, 0, height / 3, width, height / 3 );
201 SDL_RenderDrawLine( renderer, 0, height * 2 / 3, width, height * 2 / 3 );
203 SDL_RenderDrawLine( renderer, width / 3, 0, width / 3, height );
204 SDL_RenderDrawLine( renderer, width * 2 / 3, 0, width * 2 / 3, height );
208 SDL_RenderPresent(renderer);
211 int main(int argc, char* argv[])
213 // string fname(argv[1] ? argv[1] : "out.yuv");
214 // size_t width = atoi(argv[2] ? argv[2] : "1280");
215 // size_t height = atoi(argv[3] ? argv[3] : "720");
217 // int fps = atoi(argv[4] ? argv[4] : "20");
218 // cout << fname << "\n" << width << "\n" << height << "\n" << fps << "\n" << endl;
220 YuvPlayer player(1280, 720);
221 player.play("out.yuv", 25);
222 //player.play(fname);