video-io.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /******************************************************************************
  2. Copyright (C) 2013 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include <assert.h>
  15. #include "../util/bmem.h"
  16. #include "../util/platform.h"
  17. #include "../util/threading.h"
  18. #include "video-io.h"
  19. struct video_output {
  20. struct video_info info;
  21. media_t media;
  22. media_output_t output;
  23. pthread_t thread;
  24. pthread_mutex_t data_mutex;
  25. event_t stop_event;
  26. struct video_frame *cur_frame;
  27. struct video_frame *next_frame;
  28. event_t update_event;
  29. uint64_t frame_time;
  30. volatile uint64_t cur_video_time;
  31. bool initialized;
  32. };
  33. /* ------------------------------------------------------------------------- */
  34. static inline void video_swapframes(struct video_output *video)
  35. {
  36. pthread_mutex_lock(&video->data_mutex);
  37. if (video->next_frame) {
  38. video->cur_frame = video->next_frame;
  39. video->next_frame = NULL;
  40. }
  41. pthread_mutex_unlock(&video->data_mutex);
  42. }
  43. static void *video_thread(void *param)
  44. {
  45. struct video_output *video = param;
  46. uint64_t cur_time = os_gettime_ns();
  47. while (event_try(&video->stop_event) == EAGAIN) {
  48. /* wait half a frame, update frame */
  49. os_sleepto_ns(cur_time += (video->frame_time/2));
  50. video->cur_video_time = cur_time;
  51. event_signal(&video->update_event);
  52. /* wait another half a frame, swap and output frames */
  53. os_sleepto_ns(cur_time += (video->frame_time/2));
  54. video_swapframes(video);
  55. if (video->cur_frame)
  56. media_output_data(video->output, video->cur_frame);
  57. }
  58. return NULL;
  59. }
  60. /* ------------------------------------------------------------------------- */
  61. static inline bool valid_video_params(struct video_info *info)
  62. {
  63. return info->height != 0 && info->width != 0 && info->fps_den != 0 &&
  64. info->fps_num != 0 && info->format != NULL;
  65. }
  66. static inline bool vo_add_to_media(video_t video)
  67. {
  68. struct media_output_info oi;
  69. oi.format = video->info.format;
  70. oi.obj = video;
  71. oi.connect = NULL;
  72. video->output = media_output_create(&oi);
  73. if (!video->output)
  74. return false;
  75. media_add_output(video->media, video->output);
  76. return true;
  77. }
  78. int video_output_open(video_t *video, media_t media, struct video_info *info)
  79. {
  80. struct video_output *out;
  81. if (!valid_video_params(info))
  82. return VIDEO_OUTPUT_INVALIDPARAM;
  83. out = bmalloc(sizeof(struct video_output));
  84. memset(out, 0, sizeof(struct video_output));
  85. memcpy(&out->info, info, sizeof(struct video_info));
  86. out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
  87. (double)info->fps_num);
  88. out->media = media;
  89. out->initialized = false;
  90. if (pthread_mutex_init(&out->data_mutex, NULL) != 0)
  91. goto fail;
  92. if (event_init(&out->stop_event, true) != 0)
  93. goto fail;
  94. if (event_init(&out->update_event, false) != 0)
  95. goto fail;
  96. if (!vo_add_to_media(out))
  97. goto fail;
  98. if (pthread_create(&out->thread, NULL, video_thread, out) != 0)
  99. goto fail;
  100. out->initialized = true;
  101. *video = out;
  102. return VIDEO_OUTPUT_SUCCESS;
  103. fail:
  104. video_output_close(out);
  105. return VIDEO_OUTPUT_FAIL;
  106. }
  107. void video_output_frame(video_t video, struct video_frame *frame)
  108. {
  109. pthread_mutex_lock(&video->data_mutex);
  110. video->next_frame = frame;
  111. pthread_mutex_unlock(&video->data_mutex);
  112. }
  113. bool video_output_wait(video_t video)
  114. {
  115. event_wait(&video->update_event);
  116. return event_try(&video->stop_event) == EAGAIN;
  117. }
  118. uint64_t video_getframetime(video_t video)
  119. {
  120. return video->frame_time;
  121. }
  122. uint64_t video_gettime(video_t video)
  123. {
  124. return video->cur_video_time;
  125. }
  126. void video_output_stop(video_t video)
  127. {
  128. void *thread_ret;
  129. if (!video)
  130. return;
  131. if (video->initialized) {
  132. event_signal(&video->stop_event);
  133. pthread_join(video->thread, &thread_ret);
  134. event_signal(&video->update_event);
  135. }
  136. }
  137. void video_output_close(video_t video)
  138. {
  139. if (!video)
  140. return;
  141. video_output_stop(video);
  142. if (video->output) {
  143. media_remove_output(video->media, video->output);
  144. media_output_destroy(video->output);
  145. }
  146. event_destroy(&video->update_event);
  147. event_destroy(&video->stop_event);
  148. pthread_mutex_destroy(&video->data_mutex);
  149. bfree(video);
  150. }