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.

134 lines
3.7KB

  1. /*
  2. * Copyright (c) 2004 François Revol <revol@free.fr>
  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. //#define DEBUG
  20. #include "avcodec.h"
  21. #include "common.h"
  22. #include <OS.h>
  23. typedef struct ThreadContext{
  24. AVCodecContext *avctx;
  25. thread_id thread;
  26. sem_id work_sem;
  27. sem_id done_sem;
  28. int (*func)(AVCodecContext *c, void *arg);
  29. void *arg;
  30. int ret;
  31. }ThreadContext;
  32. static int32 ff_thread_func(void *v){
  33. ThreadContext *c= v;
  34. for(;;){
  35. //printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
  36. acquire_sem(c->work_sem);
  37. //printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
  38. if(c->func)
  39. c->ret= c->func(c->avctx, c->arg);
  40. else
  41. return 0;
  42. //printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
  43. release_sem(c->done_sem);
  44. }
  45. return B_OK;
  46. }
  47. /**
  48. * free what has been allocated by avcodec_thread_init().
  49. * must be called after decoding has finished, especially dont call while avcodec_thread_execute() is running
  50. */
  51. void avcodec_thread_free(AVCodecContext *s){
  52. ThreadContext *c= s->thread_opaque;
  53. int i;
  54. int32 ret;
  55. for(i=0; i<s->thread_count; i++){
  56. c[i].func= NULL;
  57. release_sem(c[i].work_sem);
  58. wait_for_thread(c[i].thread, &ret);
  59. if(c[i].work_sem > B_OK) delete_sem(c[i].work_sem);
  60. if(c[i].done_sem > B_OK) delete_sem(c[i].done_sem);
  61. }
  62. av_freep(&s->thread_opaque);
  63. }
  64. int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count){
  65. ThreadContext *c= s->thread_opaque;
  66. int i;
  67. assert(s == c->avctx);
  68. assert(count <= s->thread_count);
  69. /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
  70. for(i=0; i<count; i++){
  71. c[i].arg= arg[i];
  72. c[i].func= func;
  73. c[i].ret= 12345;
  74. release_sem(c[i].work_sem);
  75. }
  76. for(i=0; i<count; i++){
  77. acquire_sem(c[i].done_sem);
  78. c[i].func= NULL;
  79. if(ret) ret[i]= c[i].ret;
  80. }
  81. return 0;
  82. }
  83. int avcodec_thread_init(AVCodecContext *s, int thread_count){
  84. int i;
  85. ThreadContext *c;
  86. s->thread_count= thread_count;
  87. assert(!s->thread_opaque);
  88. c= av_mallocz(sizeof(ThreadContext)*thread_count);
  89. s->thread_opaque= c;
  90. for(i=0; i<thread_count; i++){
  91. //printf("init semaphors %d\n", i); fflush(stdout);
  92. c[i].avctx= s;
  93. if((c[i].work_sem = create_sem(0, "ff work sem")) < B_OK)
  94. goto fail;
  95. if((c[i].done_sem = create_sem(0, "ff done sem")) < B_OK)
  96. goto fail;
  97. //printf("create thread %d\n", i); fflush(stdout);
  98. c[i].thread = spawn_thread(ff_thread_func, "libavcodec thread", B_LOW_PRIORITY, &c[i] );
  99. if( c[i].thread < B_OK ) goto fail;
  100. resume_thread(c[i].thread );
  101. }
  102. //printf("init done\n"); fflush(stdout);
  103. s->execute= avcodec_thread_execute;
  104. return 0;
  105. fail:
  106. avcodec_thread_free(s);
  107. return -1;
  108. }