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);
33 bool readFrame(ifstream& in, uint8_t *raw, size_t size);
34 void updateRenderer(uint8_t *raw);
39 SDL_Renderer *renderer;
41 unsigned int frameCnt = 0;
43 ifstream::pos_type last_pos;
47 class ImageOperation {
49 ImageOperation(uint8_t *r, int width, int height);
58 YuvPlayer::YuvPlayer(int w, int h, const string& t)
63 SDL_Init(SDL_INIT_VIDEO);
64 window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
65 if (window == nullptr){
66 cout << "create error: " << SDL_GetError() << endl;
68 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
69 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
72 YuvPlayer::~YuvPlayer()
74 SDL_DestroyTexture(texture);
75 SDL_DestroyRenderer(renderer);
76 SDL_DestroyWindow(window);
80 void YuvPlayer::play(string file, int fps)
82 size_t frame_size = width * height * 3 / 2;
83 uint8_t *raw = (uint8_t *) malloc(sizeof(uint8_t) * frame_size);
84 ifstream in (file, ios::binary);
86 cout << "failed to open " << file << endl;
92 bool isPlaying = true;
93 int interval = 1000 / fps;
96 interval = isPlaying ? 1000 / fps : -1;
97 SDL_WaitEventTimeout(&event, interval);
98 if(fps > 0 && isPlaying){
99 if(readFrame(in, raw, frame_size)){
108 switch(event.key.keysym.sym){
113 if(readFrame(in, raw, frame_size)){
118 frameCnt = frameCnt >= 2 ? frameCnt - 2 : 0;
119 in.seekg(frameCnt * frame_size);
120 if(readFrame(in, raw, frame_size)){
126 isPlaying = !isPlaying;
141 void YuvPlayer::drawGrid()
143 // cout << "drawGrid" << endl;
144 // SDL_RenderClear(renderer);
145 // SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
147 // if(SDL_RenderDrawLine(renderer, 10, 10, 200, 200) == -1){
148 // cout << "draw line error" << endl;
150 // SDL_RenderCopy(renderer, texture, nullptr, nullptr);
151 // SDL_RenderPresent(renderer);
153 // SDL_UpdateTexture(texture, nullptr, raw, width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV));
154 SDL_RenderClear(renderer);
155 SDL_RenderCopy(renderer, texture, nullptr, nullptr);
156 SDL_RenderPresent(renderer);
160 bool YuvPlayer::readFrame(ifstream& in, uint8_t *raw, size_t size)
162 last_pos = in.tellg();
163 bool ret = (bool) in.read(reinterpret_cast<char *>(raw), size);
167 ss << this->title << " [" << setw(4) << to_string(frameCnt) << "]";
168 SDL_SetWindowTitle(window, ss.str().c_str());
170 cout << "read error" << endl;
175 void YuvPlayer::updateRenderer(uint8_t *raw)
178 memset(raw, 0x00, 1280 * 720);
180 SDL_UpdateTexture(texture, nullptr, raw, width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV));
181 SDL_RenderClear(renderer);
182 SDL_RenderCopy(renderer, texture, nullptr, nullptr);
183 SDL_RenderPresent(renderer);
186 int main(int argc, char* argv[])
188 string fname = "out.yuv";
189 YuvPlayer player(1280, 720);
190 //player.play(fname, 25);