You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.cpp 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #define GLFW_INCLUDE_GL3
  2. #define GLFW_NO_GLU
  3. #include <GL/glfw.h>
  4. #include <glm/glm.hpp>
  5. #include <glm/gtc/matrix_transform.hpp>
  6. #include <glm/gtc/type_ptr.hpp>
  7. extern "C" {
  8. #include <libavformat/avformat.h>
  9. #include <libavcodec/avcodec.h>
  10. #include <libavfilter/avfilter.h>
  11. #include <libavdevice/avdevice.h>
  12. #include <libswresample/swresample.h>
  13. #include <libswscale/swscale.h>
  14. #include <libavutil/avutil.h>
  15. #include <sys/time.h>
  16. }
  17. #include <iostream>
  18. #include <fstream>
  19. #include <string>
  20. std::string const vert_shader_source =
  21. "#version 150\n"
  22. "in vec3 vertex;\n"
  23. "in vec2 texCoord0;\n"
  24. "uniform mat4 mvpMatrix;\n"
  25. "out vec2 texCoord;\n"
  26. "void main() {\n"
  27. " gl_Position = mvpMatrix * vec4(vertex, 1.0);\n"
  28. " texCoord = texCoord0;\n"
  29. "}\n";
  30. std::string const frag_shader_source =
  31. "#version 150\n"
  32. "uniform sampler2D frameTex;\n"
  33. "in vec2 texCoord;\n"
  34. "out vec4 fragColor;\n"
  35. "void main() {\n"
  36. " fragColor = texture(frameTex, texCoord);\n"
  37. "}\n";
  38. #define BUFFER_OFFSET(i) ((char *)NULL + (i))
  39. // attribute indices
  40. enum {
  41. VERTICES = 0,
  42. TEX_COORDS
  43. };
  44. // uniform indices
  45. enum {
  46. MVP_MATRIX = 0,
  47. FRAME_TEX
  48. };
  49. // app data structure
  50. typedef struct {
  51. AVFormatContext *fmt_ctx;
  52. int stream_idx;
  53. AVStream *video_stream;
  54. AVCodecContext *codec_ctx;
  55. AVCodec *decoder;
  56. AVPacket *packet;
  57. AVFrame *av_frame;
  58. AVFrame *gl_frame;
  59. struct SwsContext *conv_ctx;
  60. GLuint vao;
  61. GLuint vert_buf;
  62. GLuint elem_buf;
  63. GLuint frame_tex;
  64. GLuint program;
  65. GLuint attribs[2];
  66. GLuint uniforms[2];
  67. } AppData;
  68. // initialize the app data structure
  69. void initializeAppData(AppData *data) {
  70. data->fmt_ctx = NULL;
  71. data->stream_idx = -1;
  72. data->video_stream = NULL;
  73. data->codec_ctx = NULL;
  74. data->decoder = NULL;
  75. data->av_frame = NULL;
  76. data->gl_frame = NULL;
  77. data->conv_ctx = NULL;
  78. }
  79. // clean up the app data structure
  80. void clearAppData(AppData *data) {
  81. if (data->av_frame) av_free(data->av_frame);
  82. if (data->gl_frame) av_free(data->gl_frame);
  83. if (data->packet) av_free(data->packet);
  84. if (data->codec_ctx) avcodec_close(data->codec_ctx);
  85. if (data->fmt_ctx) avformat_free_context(data->fmt_ctx);
  86. glDeleteVertexArrays(1, &data->vao);
  87. glDeleteBuffers(1, &data->vert_buf);
  88. glDeleteBuffers(1, &data->elem_buf);
  89. glDeleteTextures(1, &data->frame_tex);
  90. initializeAppData(data);
  91. }
  92. // read a video frame
  93. bool readFrame(AppData *data) {
  94. do {
  95. if (av_read_frame(data->fmt_ctx, data->packet) < 0) {
  96. av_free_packet(data->packet);
  97. return false;
  98. }
  99. if (data->packet->stream_index == data->stream_idx) {
  100. int frame_finished = 0;
  101. if (avcodec_decode_video2(data->codec_ctx, data->av_frame, &frame_finished,
  102. data->packet) < 0) {
  103. av_free_packet(data->packet);
  104. return false;
  105. }
  106. if (frame_finished) {
  107. if (!data->conv_ctx) {
  108. data->conv_ctx = sws_getContext(data->codec_ctx->width,
  109. data->codec_ctx->height, data->codec_ctx->pix_fmt,
  110. data->codec_ctx->width, data->codec_ctx->height, PIX_FMT_RGB24,
  111. SWS_BICUBIC, NULL, NULL, NULL);
  112. }
  113. sws_scale(data->conv_ctx, data->av_frame->data, data->av_frame->linesize, 0,
  114. data->codec_ctx->height, data->gl_frame->data, data->gl_frame->linesize);
  115. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data->codec_ctx->width,
  116. data->codec_ctx->height, GL_RGB, GL_UNSIGNED_BYTE,
  117. data->gl_frame->data[0]);
  118. }
  119. }
  120. av_free_packet(data->packet);
  121. } while (data->packet->stream_index != data->stream_idx);
  122. return true;
  123. }
  124. bool buildShader(std::string const &shader_source, GLuint &shader, GLenum type) {
  125. int size = shader_source.length();
  126. shader = glCreateShader(type);
  127. char const *c_shader_source = shader_source.c_str();
  128. glShaderSource(shader, 1, (GLchar const **)&c_shader_source, &size);
  129. glCompileShader(shader);
  130. GLint status;
  131. glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
  132. if (status != GL_TRUE) {
  133. std::cout << "failed to compile shader" << std::endl;
  134. int length;
  135. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
  136. char *log = new char[length];
  137. glGetShaderInfoLog(shader, length, &length, log);
  138. std::cout << log << std::endl;
  139. delete[] log;
  140. return false;
  141. }
  142. return true;
  143. }
  144. // initialize shaders
  145. bool buildProgram(AppData *data) {
  146. GLuint v_shader, f_shader;
  147. if (!buildShader(vert_shader_source, v_shader, GL_VERTEX_SHADER)) {
  148. std::cout << "failed to build vertex shader" << std::endl;
  149. return false;
  150. }
  151. if (!buildShader(frag_shader_source, f_shader, GL_FRAGMENT_SHADER)) {
  152. std::cout << "failed to build fragment shader" << std::endl;
  153. return false;
  154. }
  155. data->program = glCreateProgram();
  156. glAttachShader(data->program, v_shader);
  157. glAttachShader(data->program, f_shader);
  158. glLinkProgram(data->program);
  159. GLint status;
  160. glGetProgramiv(data->program, GL_LINK_STATUS, &status);
  161. if (status != GL_TRUE) {
  162. std::cout << "failed to link program" << std::endl;
  163. int length;
  164. glGetProgramiv(data->program, GL_INFO_LOG_LENGTH, &length);
  165. char *log = new char[length];
  166. glGetShaderInfoLog(data->program, length, &length, log);
  167. std::cout << log << std::endl;
  168. delete[] log;
  169. return false;
  170. }
  171. data->uniforms[MVP_MATRIX] = glGetUniformLocation(data->program, "mvpMatrix");
  172. data->uniforms[FRAME_TEX] = glGetUniformLocation(data->program, "frameTex");
  173. data->attribs[VERTICES] = glGetAttribLocation(data->program, "vertex");
  174. data->attribs[TEX_COORDS] = glGetAttribLocation(data->program, "texCoord0");
  175. return true;
  176. }
  177. // draw frame in opengl context
  178. void drawFrame(AppData *data) {
  179. glClear(GL_COLOR_BUFFER_BIT);
  180. glBindTexture(GL_TEXTURE_2D, data->frame_tex);
  181. glBindVertexArray(data->vao);
  182. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
  183. glBindVertexArray(0);
  184. glfwSwapBuffers();
  185. }
  186. int main(int argc, char *argv[]) {
  187. if (argc < 2) {
  188. std::cout << "provide a filename" << std::endl;
  189. return -1;
  190. }
  191. // initialize libav
  192. av_register_all();
  193. avformat_network_init();
  194. // initialize custom data structure
  195. AppData data;
  196. initializeAppData(&data);
  197. // open video
  198. if (avformat_open_input(&data.fmt_ctx, argv[1], NULL, NULL) < 0) {
  199. std::cout << "failed to open input" << std::endl;
  200. clearAppData(&data);
  201. return -1;
  202. }
  203. // find stream info
  204. if (avformat_find_stream_info(data.fmt_ctx, NULL) < 0) {
  205. std::cout << "failed to get stream info" << std::endl;
  206. clearAppData(&data);
  207. return -1;
  208. }
  209. // dump debug info
  210. av_dump_format(data.fmt_ctx, 0, argv[1], 0);
  211. // find the video stream
  212. for (unsigned int i = 0; i < data.fmt_ctx->nb_streams; ++i)
  213. {
  214. if (data.fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  215. {
  216. data.stream_idx = i;
  217. break;
  218. }
  219. }
  220. if (data.stream_idx == -1)
  221. {
  222. std::cout << "failed to find video stream" << std::endl;
  223. clearAppData(&data);
  224. return -1;
  225. }
  226. data.video_stream = data.fmt_ctx->streams[data.stream_idx];
  227. data.codec_ctx = data.video_stream->codec;
  228. // find the decoder
  229. data.decoder = avcodec_find_decoder(data.codec_ctx->codec_id);
  230. if (data.decoder == NULL)
  231. {
  232. std::cout << "failed to find decoder" << std::endl;
  233. clearAppData(&data);
  234. return -1;
  235. }
  236. // open the decoder
  237. if (avcodec_open2(data.codec_ctx, data.decoder, NULL) < 0)
  238. {
  239. std::cout << "failed to open codec" << std::endl;
  240. clearAppData(&data);
  241. return -1;
  242. }
  243. // allocate the video frames
  244. data.av_frame = avcodec_alloc_frame();
  245. data.gl_frame = avcodec_alloc_frame();
  246. int size = avpicture_get_size(PIX_FMT_RGB24, data.codec_ctx->width,
  247. data.codec_ctx->height);
  248. uint8_t *internal_buffer = (uint8_t *)av_malloc(size * sizeof(uint8_t));
  249. avpicture_fill((AVPicture *)data.gl_frame, internal_buffer, PIX_FMT_RGB24,
  250. data.codec_ctx->width, data.codec_ctx->height);
  251. data.packet = (AVPacket *)av_malloc(sizeof(AVPacket));
  252. // initialize glfw
  253. if (!glfwInit()) {
  254. std::cout << "glfw failed to init" << std::endl;
  255. glfwTerminate();
  256. clearAppData(&data);
  257. return -1;
  258. }
  259. // open a window
  260. float aspect = (float)data.codec_ctx->width / (float)data.codec_ctx->height;
  261. int adj_width = aspect * 300;
  262. int adj_height = 300;
  263. glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
  264. glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
  265. glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  266. glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  267. if (!glfwOpenWindow(adj_width, adj_height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) {
  268. std::cout << "failed to open window" << std::endl;
  269. glfwTerminate();
  270. clearAppData(&data);
  271. return -1;
  272. }
  273. // initialize opengl
  274. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  275. glEnable(GL_TEXTURE_2D);
  276. // initialize shaders
  277. if (!buildProgram(&data)) {
  278. std::cout << "failed to initialize shaders" << std::endl;
  279. glfwTerminate();
  280. clearAppData(&data);
  281. return -1;
  282. }
  283. glUseProgram(data.program);
  284. // initialize renderable
  285. glGenVertexArrays(1, &data.vao);
  286. glBindVertexArray(data.vao);
  287. glGenBuffers(1, &data.vert_buf);
  288. glBindBuffer(GL_ARRAY_BUFFER, data.vert_buf);
  289. float quad[20] = {
  290. -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
  291. -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
  292. 1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
  293. 1.0f, 1.0f, 0.0f, 1.0f, 0.0f
  294. };
  295. glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
  296. glVertexAttribPointer(data.attribs[VERTICES], 3, GL_FLOAT, GL_FALSE, 20,
  297. BUFFER_OFFSET(0));
  298. glEnableVertexAttribArray(data.attribs[VERTICES]);
  299. glVertexAttribPointer(data.attribs[TEX_COORDS], 2, GL_FLOAT, GL_FALSE, 20,
  300. BUFFER_OFFSET(12));
  301. glEnableVertexAttribArray(data.attribs[TEX_COORDS]);
  302. glGenBuffers(1, &data.elem_buf);
  303. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.elem_buf);
  304. unsigned char elem[6] = {
  305. 0, 1, 2,
  306. 0, 2, 3
  307. };
  308. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elem), elem, GL_STATIC_DRAW);
  309. glBindVertexArray(0);
  310. glActiveTexture(GL_TEXTURE0);
  311. glGenTextures(1, &data.frame_tex);
  312. glBindTexture(GL_TEXTURE_2D, data.frame_tex);
  313. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  314. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  315. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  316. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  317. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  318. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, data.codec_ctx->width, data.codec_ctx->height,
  319. 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
  320. glUniform1i(data.uniforms[FRAME_TEX], 0);
  321. glm::mat4 mvp = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
  322. glUniformMatrix4fv(data.uniforms[MVP_MATRIX], 1, GL_FALSE, glm::value_ptr(mvp));
  323. bool running = true;
  324. // run the application mainloop
  325. while (readFrame(&data) && running) {
  326. running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
  327. drawFrame(&data);
  328. }
  329. avformat_close_input(&data.fmt_ctx);
  330. // clean up
  331. glfwTerminate();
  332. clearAppData(&data);
  333. }