main.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * main.c
  3. * https://gitlab.com/bztsrc/sdlogv
  4. *
  5. * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to
  9. * deal in the Software without restriction, including without limitation the
  10. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  11. * sell copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
  20. * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  22. * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * @brief A simple videoplayer that uses my theora.h wrapper
  25. *
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <signal.h>
  30. #include <SDL2/SDL.h>
  31. #include <SDL2/SDL_mixer.h>
  32. #include "theora.h"
  33. /**
  34. * The decoder context. Must be global because SDL mixer callbacks know no better
  35. */
  36. theora_t ctx = { 0 };
  37. /**
  38. * The SDL mixer's callback, which, thanks to the wrapper is brainfuck simple.
  39. */
  40. static void callback(int channel)
  41. {
  42. Mix_Chunk *audio = theora_audio(&ctx);
  43. /* could we get some audio data? If so, play it! */
  44. if(audio)
  45. Mix_PlayChannel(channel, audio, 0);
  46. }
  47. /* just sets a flag */
  48. int got_sigint = 0;
  49. static void sigint_handler (int signal) { got_sigint = signal; }
  50. /**
  51. * Example on how to use the wrapper
  52. */
  53. int main(int argc, char **argv)
  54. {
  55. FILE *f;
  56. SDL_Renderer *renderer = NULL; /* the usual SDL stuff. */
  57. SDL_Texture *texture = NULL;
  58. SDL_Window *window = NULL;
  59. SDL_Event event;
  60. SDL_DisplayMode dm;
  61. SDL_Rect rect; /* the rectangle where we want to display the video */
  62. /* check arguments */
  63. if(argc < 2) {
  64. printf("./sdlogv <ogg/ogv file>\n");
  65. exit(0);
  66. }
  67. /* open the video file */
  68. f = fopen(argv[1], "rb");
  69. if(!f) {
  70. fprintf(stderr, "unable to open file\n");
  71. exit(1);
  72. }
  73. /************************************************************************/
  74. /*** get the duration in millisec ***/
  75. /************************************************************************/
  76. printf("Duration: %lu msec\n", theora_getduration(f));
  77. /* nothing to see here, please move on, just initialize SDL2 and SDL mixer */
  78. SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_EVENTS);
  79. SDL_GetDesktopDisplayMode(0, &dm);
  80. Mix_Init(0);
  81. Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 4096);
  82. /************************************************************************/
  83. /*** start the decoder ***/
  84. /************************************************************************/
  85. /* yeah, really this simple. */
  86. theora_start(&ctx, f);
  87. /* Is there a video stream in the file? If so, open a window and create a texture where we will paint the video */
  88. if(ctx.hasVideo) {
  89. SDL_GetDesktopDisplayMode(0, &dm);
  90. window = SDL_CreateWindow("sdlogv", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w, dm.h, SDL_WINDOW_FULLSCREEN);
  91. renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  92. /* the decoder was kind enough to tell us the video dimensions in advance */
  93. texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, ctx.w, ctx.h);
  94. /* fit it to our screen centered keeping aspect ratio */
  95. rect.w = dm.w; rect.h = ctx.h * dm.w / ctx.w;
  96. if(rect.h > dm.h) { rect.h = dm.h; rect.w = ctx.w * dm.h / ctx.h; }
  97. rect.x = (dm.w - rect.w) / 2; rect.y = (dm.h - rect.h) / 2;
  98. } else {
  99. /* in lack of a window, SDL can't handle keypress events. */
  100. signal(SIGINT, sigint_handler);
  101. }
  102. /************************************************************************/
  103. /*** audio player ***/
  104. /************************************************************************/
  105. /* this is going to be extremely simple, because we're using SDL mixer to play it in the background */
  106. if(ctx.hasAudio) {
  107. Mix_ChannelFinished(callback);
  108. callback(0);
  109. }
  110. /************************************************************************/
  111. /*** video player ***/
  112. /************************************************************************/
  113. printf("Playing started...\n");
  114. /* in this simple example, we quit when we are finished playing, but you don't have to */
  115. while (theora_playing(&ctx) && !got_sigint) {
  116. /* is there a frame to play? If so, refresh the texture */
  117. theora_video(&ctx, texture);
  118. /* handle some events... */
  119. SDL_PollEvent(&event);
  120. if(event.type == SDL_QUIT || event.type == SDL_KEYUP || event.type == SDL_MOUSEBUTTONDOWN) break;
  121. /* render as usual. The video is just another texture to add. You could resize and position it if you want */
  122. SDL_RenderClear(renderer);
  123. SDL_RenderCopy(renderer, texture, NULL, &rect);
  124. SDL_RenderPresent(renderer);
  125. }
  126. printf("Finished playing\n");
  127. /************************************************************************/
  128. /*** stop the decoder ***/
  129. /************************************************************************/
  130. /* the theora thread has absolutely no clue about the SDL mixer usings its buffers, so we MUST stop the mixer first. */
  131. if(Mix_Playing(-1)) {
  132. Mix_ChannelFinished(NULL);
  133. Mix_HaltChannel(-1);
  134. }
  135. /* ok, now that nobody is relying on the audio buffer, we can stop the decoder and destroy the context */
  136. theora_stop(&ctx);
  137. /* as usual, free SDL resources */
  138. printf("Tear down\n");
  139. fclose(f);
  140. if(texture) SDL_DestroyTexture(texture);
  141. if(renderer) SDL_DestroyRenderer(renderer);
  142. if(window) SDL_DestroyWindow(window);
  143. Mix_CloseAudio();
  144. Mix_Quit();
  145. SDL_Quit();
  146. return 0;
  147. }