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.

182 lines
4.7KB

  1. /*
  2. * Copyright (c) 2004 François Revol <revol@free.fr>
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. //#define DEBUG
  22. #include "avcodec.h"
  23. #include <OS.h>
  24. typedef struct ThreadContext{
  25. AVCodecContext *avctx;
  26. thread_id thread;
  27. sem_id work_sem;
  28. sem_id done_sem;
  29. int (*func)(AVCodecContext *c, void *arg);
  30. void *arg;
  31. int ret;
  32. }ThreadContext;
  33. // it's odd Be never patented that :D
  34. struct benaphore {
  35. vint32 atom;
  36. sem_id sem;
  37. };
  38. static inline int lock_ben(struct benaphore *ben)
  39. {
  40. if (atomic_add(&ben->atom, 1) > 0)
  41. return acquire_sem(ben->sem);
  42. return B_OK;
  43. }
  44. static inline int unlock_ben(struct benaphore *ben)
  45. {
  46. if (atomic_add(&ben->atom, -1) > 1)
  47. return release_sem(ben->sem);
  48. return B_OK;
  49. }
  50. static struct benaphore av_thread_lib_ben;
  51. static int32 ff_thread_func(void *v){
  52. ThreadContext *c= v;
  53. for(;;){
  54. //printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
  55. acquire_sem(c->work_sem);
  56. //printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
  57. if(c->func)
  58. c->ret= c->func(c->avctx, c->arg);
  59. else
  60. return 0;
  61. //printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
  62. release_sem(c->done_sem);
  63. }
  64. return B_OK;
  65. }
  66. /**
  67. * free what has been allocated by avcodec_thread_init().
  68. * must be called after decoding has finished, especially dont call while avcodec_thread_execute() is running
  69. */
  70. void avcodec_thread_free(AVCodecContext *s){
  71. ThreadContext *c= s->thread_opaque;
  72. int i;
  73. int32 ret;
  74. for(i=0; i<s->thread_count; i++){
  75. c[i].func= NULL;
  76. release_sem(c[i].work_sem);
  77. wait_for_thread(c[i].thread, &ret);
  78. if(c[i].work_sem > B_OK) delete_sem(c[i].work_sem);
  79. if(c[i].done_sem > B_OK) delete_sem(c[i].done_sem);
  80. }
  81. av_freep(&s->thread_opaque);
  82. }
  83. int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count){
  84. ThreadContext *c= s->thread_opaque;
  85. int i;
  86. assert(s == c->avctx);
  87. assert(count <= s->thread_count);
  88. /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
  89. for(i=0; i<count; i++){
  90. c[i].arg= arg[i];
  91. c[i].func= func;
  92. c[i].ret= 12345;
  93. release_sem(c[i].work_sem);
  94. }
  95. for(i=0; i<count; i++){
  96. acquire_sem(c[i].done_sem);
  97. c[i].func= NULL;
  98. if(ret) ret[i]= c[i].ret;
  99. }
  100. return 0;
  101. }
  102. int avcodec_thread_init(AVCodecContext *s, int thread_count){
  103. int i;
  104. ThreadContext *c;
  105. s->thread_count= thread_count;
  106. assert(!s->thread_opaque);
  107. c= av_mallocz(sizeof(ThreadContext)*thread_count);
  108. s->thread_opaque= c;
  109. for(i=0; i<thread_count; i++){
  110. //printf("init semaphors %d\n", i); fflush(stdout);
  111. c[i].avctx= s;
  112. if((c[i].work_sem = create_sem(0, "ff work sem")) < B_OK)
  113. goto fail;
  114. if((c[i].done_sem = create_sem(0, "ff done sem")) < B_OK)
  115. goto fail;
  116. //printf("create thread %d\n", i); fflush(stdout);
  117. c[i].thread = spawn_thread(ff_thread_func, "libavcodec thread", B_LOW_PRIORITY, &c[i] );
  118. if( c[i].thread < B_OK ) goto fail;
  119. resume_thread(c[i].thread );
  120. }
  121. //printf("init done\n"); fflush(stdout);
  122. s->execute= avcodec_thread_execute;
  123. return 0;
  124. fail:
  125. avcodec_thread_free(s);
  126. return -1;
  127. }
  128. /* provide a mean to serialize calls to avcodec_*() for thread safety. */
  129. int avcodec_thread_lock_lib(void)
  130. {
  131. return lock_ben(&av_thread_lib_ben);
  132. }
  133. int avcodec_thread_unlock_lib(void)
  134. {
  135. return unlock_ben(&av_thread_lib_ben);
  136. }
  137. /* our versions of _init and _fini (which are called by those actually from crt.o) */
  138. void initialize_after(void)
  139. {
  140. av_thread_lib_ben.atom = 0;
  141. av_thread_lib_ben.sem = create_sem(0, "libavcodec benaphore");
  142. }
  143. void uninitialize_before(void)
  144. {
  145. delete_sem(av_thread_lib_ben.sem);
  146. }