video-io.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 2 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;
  65. }
  66. static inline bool vo_add_to_media(video_t video)
  67. {
  68. struct media_output_info oi;
  69. oi.obj = video;
  70. oi.connect = NULL;
  71. video->output = media_output_create(&oi);
  72. if (!video->output)
  73. return false;
  74. media_add_output(video->media, video->output);
  75. return true;
  76. }
  77. int video_output_open(video_t *video, media_t media, struct video_info *info)
  78. {
  79. struct video_output *out;
  80. if (!valid_video_params(info))
  81. return VIDEO_OUTPUT_INVALIDPARAM;
  82. out = bmalloc(sizeof(struct video_output));
  83. memset(out, 0, sizeof(struct video_output));
  84. memcpy(&out->info, info, sizeof(struct video_info));
  85. out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
  86. (double)info->fps_num);
  87. out->media = media;
  88. out->initialized = false;
  89. if (pthread_mutex_init(&out->data_mutex, NULL) != 0)
  90. goto fail;
  91. if (event_init(&out->stop_event, true) != 0)
  92. goto fail;
  93. if (event_init(&out->update_event, false) != 0)
  94. goto fail;
  95. if (!vo_add_to_media(out))
  96. goto fail;
  97. if (pthread_create(&out->thread, NULL, video_thread, out) != 0)
  98. goto fail;
  99. out->initialized = true;
  100. *video = out;
  101. return VIDEO_OUTPUT_SUCCESS;
  102. fail:
  103. video_output_close(out);
  104. return VIDEO_OUTPUT_FAIL;
  105. }
  106. const struct video_info *video_output_getinfo(video_t video)
  107. {
  108. return &video->info;
  109. }
  110. void video_output_frame(video_t video, struct video_frame *frame)
  111. {
  112. pthread_mutex_lock(&video->data_mutex);
  113. video->next_frame = frame;
  114. pthread_mutex_unlock(&video->data_mutex);
  115. }
  116. bool video_output_wait(video_t video)
  117. {
  118. event_wait(&video->update_event);
  119. return event_try(&video->stop_event) == EAGAIN;
  120. }
  121. uint64_t video_getframetime(video_t video)
  122. {
  123. return video->frame_time;
  124. }
  125. uint64_t video_gettime(video_t video)
  126. {
  127. return video->cur_video_time;
  128. }
  129. void video_output_stop(video_t video)
  130. {
  131. void *thread_ret;
  132. if (!video)
  133. return;
  134. if (video->initialized) {
  135. event_signal(&video->stop_event);
  136. pthread_join(video->thread, &thread_ret);
  137. event_signal(&video->update_event);
  138. }
  139. }
  140. void video_output_close(video_t video)
  141. {
  142. if (!video)
  143. return;
  144. video_output_stop(video);
  145. if (video->output) {
  146. media_remove_output(video->media, video->output);
  147. media_output_destroy(video->output);
  148. }
  149. event_destroy(&video->update_event);
  150. event_destroy(&video->stop_event);
  151. pthread_mutex_destroy(&video->data_mutex);
  152. bfree(video);
  153. }