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.

140 lines
3.9KB

  1. /*
  2. * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. */
  19. #include <semaphore.h>
  20. #include <pthread.h>
  21. //#define DEBUG
  22. #include "avcodec.h"
  23. #include "common.h"
  24. typedef struct ThreadContext{
  25. AVCodecContext *avctx;
  26. pthread_t thread;
  27. sem_t work_sem;
  28. sem_t done_sem;
  29. int (*func)(AVCodecContext *c, void *arg);
  30. void *arg;
  31. int ret;
  32. }ThreadContext;
  33. static void * thread_func(void *v){
  34. ThreadContext *c= v;
  35. for(;;){
  36. //printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
  37. sem_wait(&c->work_sem);
  38. //printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
  39. if(c->func)
  40. c->ret= c->func(c->avctx, c->arg);
  41. else
  42. return NULL;
  43. //printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
  44. sem_post(&c->done_sem);
  45. }
  46. return NULL;
  47. }
  48. /**
  49. * free what has been allocated by avcodec_thread_init().
  50. * must be called after decoding has finished, especially dont call while avcodec_thread_execute() is running
  51. */
  52. void avcodec_thread_free(AVCodecContext *s){
  53. ThreadContext *c= s->thread_opaque;
  54. int i;
  55. for(i=0; i<s->thread_count; i++){
  56. int val;
  57. sem_getvalue(&c[i].work_sem, &val); assert(val == 0);
  58. sem_getvalue(&c[i].done_sem, &val); assert(val == 0);
  59. c[i].func= NULL;
  60. sem_post(&c[i].work_sem);
  61. pthread_join(c[i].thread, NULL);
  62. sem_destroy(&c[i].work_sem);
  63. sem_destroy(&c[i].done_sem);
  64. }
  65. av_freep(&s->thread_opaque);
  66. }
  67. int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count){
  68. ThreadContext *c= s->thread_opaque;
  69. int i, val;
  70. assert(s == c->avctx);
  71. assert(count <= s->thread_count);
  72. /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
  73. for(i=0; i<count; i++){
  74. sem_getvalue(&c[i].work_sem, &val); assert(val == 0);
  75. sem_getvalue(&c[i].done_sem, &val); assert(val == 0);
  76. c[i].arg= arg[i];
  77. c[i].func= func;
  78. c[i].ret= 12345;
  79. sem_post(&c[i].work_sem);
  80. }
  81. for(i=0; i<count; i++){
  82. sem_wait(&c[i].done_sem);
  83. sem_getvalue(&c[i].work_sem, &val); assert(val == 0);
  84. sem_getvalue(&c[i].done_sem, &val); assert(val == 0);
  85. c[i].func= NULL;
  86. if(ret) ret[i]= c[i].ret;
  87. }
  88. return 0;
  89. }
  90. int avcodec_thread_init(AVCodecContext *s, int thread_count){
  91. int i;
  92. ThreadContext *c;
  93. s->thread_count= thread_count;
  94. assert(!s->thread_opaque);
  95. c= av_mallocz(sizeof(ThreadContext)*thread_count);
  96. s->thread_opaque= c;
  97. for(i=0; i<thread_count; i++){
  98. //printf("init semaphors %d\n", i); fflush(stdout);
  99. c[i].avctx= s;
  100. if(sem_init(&c[i].work_sem, 0, 0))
  101. goto fail;
  102. if(sem_init(&c[i].done_sem, 0, 0))
  103. goto fail;
  104. //printf("create thread %d\n", i); fflush(stdout);
  105. if(pthread_create(&c[i].thread, NULL, thread_func, &c[i]))
  106. goto fail;
  107. }
  108. //printf("init done\n"); fflush(stdout);
  109. s->execute= avcodec_thread_execute;
  110. return 0;
  111. fail:
  112. avcodec_thread_free(s);
  113. return -1;
  114. }