ijksdl_codec_android_mediacodec_java.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*****************************************************************************
  2. * ijksdl_codec_android_mediacodec_java.c
  3. *****************************************************************************
  4. *
  5. * Copyright (c) 2014 Bilibili
  6. * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>
  7. *
  8. * This file is part of ijkPlayer.
  9. *
  10. * ijkPlayer is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * ijkPlayer is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with ijkPlayer; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. #include "ijksdl_codec_android_mediacodec_java.h"
  25. #include <assert.h>
  26. #include "j4a/class/android/media/MediaCodec.h"
  27. #include "ijksdl_android_jni.h"
  28. #include "ijksdl_codec_android_mediacodec_internal.h"
  29. #include "ijksdl_codec_android_mediaformat_java.h"
  30. #include "ijksdl_inc_internal_android.h"
  31. static SDL_Class g_amediacodec_class = {
  32. .name = "AMediaCodecJava",
  33. };
  34. typedef struct SDL_AMediaCodec_Opaque {
  35. jobject android_media_codec;
  36. jobject output_buffer_info;
  37. bool is_input_buffer_valid;
  38. } SDL_AMediaCodec_Opaque;
  39. jobject SDL_AMediaCodecJava_getObject(JNIEnv *env, const SDL_AMediaCodec *thiz)
  40. {
  41. if (!thiz || !thiz->opaque)
  42. return NULL;
  43. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque;
  44. return opaque->android_media_codec;
  45. }
  46. SDL_AMediaFormat *SDL_AMediaCodecJava_getOutputFormat(SDL_AMediaCodec *thiz)
  47. {
  48. if (!thiz || !thiz->opaque)
  49. return NULL;
  50. JNIEnv *env = NULL;
  51. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  52. ALOGE("%s: SetupThreadEnv failed", __func__);
  53. return NULL;
  54. }
  55. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque;
  56. jobject local_android_format = J4AC_MediaCodec__getOutputFormat__catchAll(env, opaque->android_media_codec);
  57. if (!local_android_format) {
  58. return NULL;
  59. }
  60. SDL_AMediaFormat *aformat = SDL_AMediaFormatJava_init(env, local_android_format);
  61. SDL_JNI_DeleteLocalRefP(env, &local_android_format);
  62. return aformat;
  63. }
  64. static sdl_amedia_status_t SDL_AMediaCodecJava_delete(SDL_AMediaCodec* acodec)
  65. {
  66. ALOGI("%s\n", __func__);
  67. if (!acodec)
  68. return SDL_AMEDIA_OK;
  69. JNIEnv *env = NULL;
  70. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  71. ALOGE("SDL_AMediaCodecJava_delete: SetupThreadEnv failed");
  72. return SDL_AMEDIA_ERROR_UNKNOWN;
  73. }
  74. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  75. if (opaque) {
  76. if (opaque->android_media_codec) {
  77. J4AC_MediaCodec__release__catchAll(env, opaque->android_media_codec);
  78. }
  79. SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_info);
  80. SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_codec);
  81. }
  82. SDL_AMediaCodec_FreeInternal(acodec);
  83. return SDL_AMEDIA_OK;
  84. }
  85. static sdl_amedia_status_t SDL_AMediaCodecJava_configure_surface(
  86. JNIEnv*env,
  87. SDL_AMediaCodec* acodec,
  88. const SDL_AMediaFormat* aformat,
  89. jobject android_surface,
  90. SDL_AMediaCrypto *crypto,
  91. uint32_t flags)
  92. {
  93. SDLTRACE("%s", __func__);
  94. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  95. jobject android_media_format = SDL_AMediaFormatJava_getObject(env, aformat);
  96. jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);
  97. ALOGE("configure acodec:%p format:%p: surface:%p", android_media_codec, android_media_format, android_surface);
  98. J4AC_MediaCodec__configure(env, android_media_codec, android_media_format, android_surface, crypto, flags);
  99. if (J4A_ExceptionCheck__catchAll(env)) {
  100. return SDL_AMEDIA_ERROR_UNKNOWN;
  101. }
  102. opaque->is_input_buffer_valid = true;
  103. return SDL_AMEDIA_OK;
  104. }
  105. static sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec)
  106. {
  107. SDLTRACE("%s", __func__);
  108. JNIEnv *env = NULL;
  109. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  110. ALOGE("%s: SetupThreadEnv failed", __func__);
  111. return SDL_AMEDIA_ERROR_UNKNOWN;
  112. }
  113. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  114. jobject android_media_codec = opaque->android_media_codec;
  115. J4AC_MediaCodec__start(env, android_media_codec);
  116. if (J4A_ExceptionCheck__catchAll(env)) {
  117. ALOGE("%s: start failed", __func__);
  118. return SDL_AMEDIA_ERROR_UNKNOWN;
  119. }
  120. return SDL_AMEDIA_OK;
  121. }
  122. static sdl_amedia_status_t SDL_AMediaCodecJava_stop(SDL_AMediaCodec* acodec)
  123. {
  124. SDLTRACE("%s", __func__);
  125. JNIEnv *env = NULL;
  126. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  127. ALOGE("%s: SetupThreadEnv failed", __func__);
  128. return SDL_AMEDIA_ERROR_UNKNOWN;
  129. }
  130. jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);
  131. J4AC_MediaCodec__stop(env, android_media_codec);
  132. if (J4A_ExceptionCheck__catchAll(env)) {
  133. ALOGE("%s: stop", __func__);
  134. return SDL_AMEDIA_ERROR_UNKNOWN;
  135. }
  136. acodec->object_serial = SDL_AMediaCodec_create_object_serial();
  137. return SDL_AMEDIA_OK;
  138. }
  139. static sdl_amedia_status_t SDL_AMediaCodecJava_flush(SDL_AMediaCodec* acodec)
  140. {
  141. SDLTRACE("%s", __func__);
  142. JNIEnv *env = NULL;
  143. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  144. ALOGE("%s: SetupThreadEnv failed", __func__);
  145. return SDL_AMEDIA_ERROR_UNKNOWN;
  146. }
  147. jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);
  148. J4AC_MediaCodec__flush(env, android_media_codec);
  149. if (J4A_ExceptionCheck__catchAll(env)) {
  150. ALOGE("%s: flush", __func__);
  151. return SDL_AMEDIA_ERROR_UNKNOWN;
  152. }
  153. acodec->object_serial = SDL_AMediaCodec_create_object_serial();
  154. return SDL_AMEDIA_OK;
  155. }
  156. static ssize_t SDL_AMediaCodecJava_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size)
  157. {
  158. AMCTRACE("%s", __func__);
  159. ssize_t write_ret = -1;
  160. jobject input_buffer_array = NULL;
  161. jobject input_buffer = NULL;
  162. JNIEnv *env = NULL;
  163. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  164. ALOGE("%s: SetupThreadEnv failed", __func__);
  165. return -1;
  166. }
  167. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  168. input_buffer_array = J4AC_MediaCodec__getInputBuffers__catchAll(env, opaque->android_media_codec);
  169. if (!input_buffer_array)
  170. return -1;
  171. int buffer_count = (*env)->GetArrayLength(env, input_buffer_array);
  172. if (J4A_ExceptionCheck__catchAll(env) || idx < 0 || idx >= buffer_count) {
  173. ALOGE("%s: idx(%d) < count(%d)\n", __func__, (int)idx, (int)buffer_count);
  174. goto fail;
  175. }
  176. input_buffer = (*env)->GetObjectArrayElement(env, input_buffer_array, idx);
  177. if (J4A_ExceptionCheck__catchAll(env) || !input_buffer) {
  178. ALOGE("%s: GetObjectArrayElement failed\n", __func__);
  179. goto fail;
  180. }
  181. {
  182. jlong buf_size = (*env)->GetDirectBufferCapacity(env, input_buffer);
  183. void *buf_ptr = (*env)->GetDirectBufferAddress(env, input_buffer);
  184. write_ret = size < buf_size ? size : buf_size;
  185. memcpy(buf_ptr, data, write_ret);
  186. }
  187. fail:
  188. SDL_JNI_DeleteLocalRefP(env, &input_buffer);
  189. SDL_JNI_DeleteLocalRefP(env, &input_buffer_array);
  190. return write_ret;
  191. }
  192. ssize_t SDL_AMediaCodecJava_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs)
  193. {
  194. AMCTRACE("%s(%d)", __func__, (int)timeoutUs);
  195. JNIEnv *env = NULL;
  196. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  197. ALOGE("%s: SetupThreadEnv failed", __func__);
  198. return -1;
  199. }
  200. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  201. // docs lie, getInputBuffers should be good after
  202. // m_codec->start() but the internal refs are not
  203. // setup until much later on some devices.
  204. //if (-1 == getInputBuffers(env, acodec)) {
  205. // ALOGE("%s: getInputBuffers failed", __func__);
  206. // return -1;
  207. //}
  208. jobject android_media_codec = opaque->android_media_codec;
  209. jint idx = J4AC_MediaCodec__dequeueInputBuffer(env, android_media_codec, (jlong)timeoutUs);
  210. if (J4A_ExceptionCheck__catchAll(env)) {
  211. ALOGE("%s: dequeueInputBuffer failed", __func__);
  212. opaque->is_input_buffer_valid = false;
  213. return -1;
  214. }
  215. return idx;
  216. }
  217. sdl_amedia_status_t SDL_AMediaCodecJava_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
  218. {
  219. AMCTRACE("%s: %d", __func__, (int)idx);
  220. JNIEnv *env = NULL;
  221. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  222. ALOGE("SDL_AMediaCodecJava_queueInputBuffer: SetupThreadEnv failed");
  223. return SDL_AMEDIA_ERROR_UNKNOWN;
  224. }
  225. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  226. jobject android_media_codec = opaque->android_media_codec;
  227. J4AC_MediaCodec__queueInputBuffer(env, android_media_codec, (jint)idx, (jint)offset, (jint)size, (jlong)time, (jint)flags);
  228. if (J4A_ExceptionCheck__catchAll(env)) {
  229. return SDL_AMEDIA_ERROR_UNKNOWN;
  230. }
  231. return SDL_AMEDIA_OK;
  232. }
  233. ssize_t SDL_AMediaCodecJava_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)
  234. {
  235. AMCTRACE("%s(%d)", __func__, (int)timeoutUs);
  236. JNIEnv *env = NULL;
  237. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  238. ALOGE("%s: SetupThreadEnv failed", __func__);
  239. return AMEDIACODEC__UNKNOWN_ERROR;
  240. }
  241. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  242. jobject android_media_codec = opaque->android_media_codec;
  243. if (!opaque->output_buffer_info) {
  244. opaque->output_buffer_info = J4AC_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(env);
  245. if (!opaque->output_buffer_info)
  246. return AMEDIACODEC__UNKNOWN_ERROR;
  247. }
  248. jint idx = AMEDIACODEC__UNKNOWN_ERROR;
  249. while (1) {
  250. idx = J4AC_MediaCodec__dequeueOutputBuffer(env, android_media_codec, opaque->output_buffer_info, (jlong)timeoutUs);
  251. if (J4A_ExceptionCheck__catchAll(env)) {
  252. ALOGI("%s: Exception\n", __func__);
  253. return AMEDIACODEC__UNKNOWN_ERROR;
  254. }
  255. if (idx == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) {
  256. ALOGI("%s: INFO_OUTPUT_BUFFERS_CHANGED\n", __func__);
  257. continue;
  258. } else if (idx == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) {
  259. ALOGI("%s: INFO_OUTPUT_FORMAT_CHANGED\n", __func__);
  260. } else if (idx >= 0) {
  261. AMCTRACE("%s: buffer ready (%d) ====================\n", __func__, idx);
  262. if (info) {
  263. info->offset = J4AC_MediaCodec__BufferInfo__offset__get__catchAll(env, opaque->output_buffer_info);
  264. info->size = J4AC_MediaCodec__BufferInfo__size__get__catchAll(env, opaque->output_buffer_info);
  265. info->presentationTimeUs = J4AC_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(env, opaque->output_buffer_info);
  266. info->flags = J4AC_MediaCodec__BufferInfo__flags__get__catchAll(env, opaque->output_buffer_info);
  267. }
  268. }
  269. break;
  270. }
  271. return idx;
  272. }
  273. sdl_amedia_status_t SDL_AMediaCodecJava_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render)
  274. {
  275. AMCTRACE("%s", __func__);
  276. JNIEnv *env = NULL;
  277. if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
  278. ALOGE("%s(%d, %s): SetupThreadEnv failed", __func__, (int)idx, render ? "true" : "false");
  279. return SDL_AMEDIA_ERROR_UNKNOWN;
  280. }
  281. SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
  282. jobject android_media_codec = opaque->android_media_codec;
  283. J4AC_MediaCodec__releaseOutputBuffer(env, android_media_codec, (jint)idx, (jboolean)render);
  284. if (J4A_ExceptionCheck__catchAll(env)) {
  285. ALOGE("%s: releaseOutputBuffer\n", __func__);
  286. return SDL_AMEDIA_ERROR_UNKNOWN;
  287. }
  288. return SDL_AMEDIA_OK;
  289. }
  290. bool SDL_AMediaCodecJava_isInputBuffersValid(SDL_AMediaCodec* acodec)
  291. {
  292. SDL_AMediaCodec_Opaque *opaque = acodec->opaque;
  293. return opaque->is_input_buffer_valid;
  294. }
  295. static SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec)
  296. {
  297. SDLTRACE("%s", __func__);
  298. jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec);
  299. if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_codec) {
  300. return NULL;
  301. }
  302. SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque));
  303. if (!acodec) {
  304. SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec);
  305. return NULL;
  306. }
  307. SDL_AMediaCodec_Opaque *opaque = acodec->opaque;
  308. opaque->android_media_codec = global_android_media_codec;
  309. acodec->opaque_class = &g_amediacodec_class;
  310. acodec->func_delete = SDL_AMediaCodecJava_delete;
  311. acodec->func_configure = NULL;
  312. acodec->func_configure_surface = SDL_AMediaCodecJava_configure_surface;
  313. acodec->func_start = SDL_AMediaCodecJava_start;
  314. acodec->func_stop = SDL_AMediaCodecJava_stop;
  315. acodec->func_flush = SDL_AMediaCodecJava_flush;
  316. acodec->func_writeInputData = SDL_AMediaCodecJava_writeInputData;
  317. acodec->func_dequeueInputBuffer = SDL_AMediaCodecJava_dequeueInputBuffer;
  318. acodec->func_queueInputBuffer = SDL_AMediaCodecJava_queueInputBuffer;
  319. acodec->func_dequeueOutputBuffer = SDL_AMediaCodecJava_dequeueOutputBuffer;
  320. acodec->func_getOutputFormat = SDL_AMediaCodecJava_getOutputFormat;
  321. acodec->func_releaseOutputBuffer = SDL_AMediaCodecJava_releaseOutputBuffer;
  322. acodec->func_isInputBuffersValid = SDL_AMediaCodecJava_isInputBuffersValid;
  323. SDL_AMediaCodec_increaseReference(acodec);
  324. return acodec;
  325. }
  326. SDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name)
  327. {
  328. SDLTRACE("%s", __func__);
  329. jobject android_media_codec = J4AC_MediaCodec__createByCodecName__withCString__catchAll(env, codec_name);
  330. if (J4A_ExceptionCheck__catchAll(env) || !android_media_codec) {
  331. return NULL;
  332. }
  333. SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, android_media_codec);
  334. acodec->object_serial = SDL_AMediaCodec_create_object_serial();
  335. SDL_JNI_DeleteLocalRefP(env, &android_media_codec);
  336. return acodec;
  337. }