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

169 lines
4.5KB

  1. /*
  2. * Copyright (c) 2004 Roman Shaposhnik.
  3. *
  4. * Many thanks to Steven M. Schultz for providing clever ideas and
  5. * to Michael Niedermayer <michaelni@gmx.at> for writing initial
  6. * implementation.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. */
  23. #include <pthread.h>
  24. #include "avcodec.h"
  25. #include "common.h"
  26. typedef int (action_t)(AVCodecContext *c, void *arg);
  27. typedef struct ThreadContext {
  28. pthread_t *workers;
  29. action_t *func;
  30. void **args;
  31. int *rets;
  32. int rets_count;
  33. int job_count;
  34. pthread_cond_t last_job_cond;
  35. pthread_cond_t current_job_cond;
  36. pthread_mutex_t current_job_lock;
  37. int current_job;
  38. int done;
  39. } ThreadContext;
  40. static void* worker(void *v)
  41. {
  42. AVCodecContext *avctx = v;
  43. ThreadContext *c = avctx->thread_opaque;
  44. int our_job = c->job_count;
  45. int thread_count = avctx->thread_count;
  46. int self_id;
  47. pthread_mutex_lock(&c->current_job_lock);
  48. self_id = c->current_job++;
  49. for (;;){
  50. while (our_job >= c->job_count) {
  51. if (c->current_job == thread_count + c->job_count)
  52. pthread_cond_signal(&c->last_job_cond);
  53. pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
  54. our_job = self_id;
  55. if (c->done) {
  56. pthread_mutex_unlock(&c->current_job_lock);
  57. return NULL;
  58. }
  59. }
  60. pthread_mutex_unlock(&c->current_job_lock);
  61. c->rets[our_job%c->rets_count] = c->func(avctx, c->args[our_job]);
  62. pthread_mutex_lock(&c->current_job_lock);
  63. our_job = c->current_job++;
  64. }
  65. }
  66. static always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
  67. {
  68. pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
  69. pthread_mutex_unlock(&c->current_job_lock);
  70. }
  71. void avcodec_thread_free(AVCodecContext *avctx)
  72. {
  73. ThreadContext *c = avctx->thread_opaque;
  74. int i;
  75. pthread_mutex_lock(&c->current_job_lock);
  76. c->done = 1;
  77. pthread_cond_broadcast(&c->current_job_cond);
  78. pthread_mutex_unlock(&c->current_job_lock);
  79. for (i=0; i<avctx->thread_count; i++)
  80. pthread_join(c->workers[i], NULL);
  81. pthread_mutex_destroy(&c->current_job_lock);
  82. pthread_cond_destroy(&c->current_job_cond);
  83. pthread_cond_destroy(&c->last_job_cond);
  84. av_free(c->workers);
  85. av_free(c);
  86. }
  87. int avcodec_thread_execute(AVCodecContext *avctx, action_t* func, void **arg, int *ret, int job_count)
  88. {
  89. ThreadContext *c= avctx->thread_opaque;
  90. int dummy_ret;
  91. if (job_count <= 0)
  92. return 0;
  93. pthread_mutex_lock(&c->current_job_lock);
  94. c->current_job = avctx->thread_count;
  95. c->job_count = job_count;
  96. c->args = arg;
  97. c->func = func;
  98. if (ret) {
  99. c->rets = ret;
  100. c->rets_count = job_count;
  101. } else {
  102. c->rets = &dummy_ret;
  103. c->rets_count = 1;
  104. }
  105. pthread_cond_broadcast(&c->current_job_cond);
  106. avcodec_thread_park_workers(c, avctx->thread_count);
  107. return 0;
  108. }
  109. int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
  110. {
  111. int i;
  112. ThreadContext *c;
  113. c = av_mallocz(sizeof(ThreadContext));
  114. if (!c)
  115. return -1;
  116. c->workers = av_mallocz(sizeof(pthread_t)*thread_count);
  117. if (!c->workers) {
  118. av_free(c);
  119. return -1;
  120. }
  121. avctx->thread_opaque = c;
  122. avctx->thread_count = thread_count;
  123. c->current_job = 0;
  124. c->job_count = 0;
  125. c->done = 0;
  126. pthread_cond_init(&c->current_job_cond, NULL);
  127. pthread_cond_init(&c->last_job_cond, NULL);
  128. pthread_mutex_init(&c->current_job_lock, NULL);
  129. pthread_mutex_lock(&c->current_job_lock);
  130. for (i=0; i<thread_count; i++) {
  131. if(pthread_create(&c->workers[i], NULL, worker, avctx)) {
  132. avctx->thread_count = i;
  133. pthread_mutex_unlock(&c->current_job_lock);
  134. avcodec_thread_free(avctx);
  135. return -1;
  136. }
  137. }
  138. avcodec_thread_park_workers(c, thread_count);
  139. avctx->execute = avcodec_thread_execute;
  140. return 0;
  141. }