1 /*
2  * Android MediaCodec public API functions
3  *
4  * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg 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.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg 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 FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "config.h"
24 
25 #include "libavutil/error.h"
26 
27 #include "mediacodec.h"
28 
29 #if CONFIG_MEDIACODEC
30 
31 #include <jni.h>
32 
33 #include "libavcodec/avcodec.h"
34 #include "libavutil/mem.h"
35 
36 #include "ffjni.h"
37 #include "mediacodecdec_common.h"
38 
av_mediacodec_alloc_context(void)39 AVMediaCodecContext *av_mediacodec_alloc_context(void)
40 {
41     return av_mallocz(sizeof(AVMediaCodecContext));
42 }
43 
av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)44 int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)
45 {
46     int ret = 0;
47     JNIEnv *env = NULL;
48 
49     env = ff_jni_get_env(avctx);
50     if (!env) {
51         return AVERROR_EXTERNAL;
52     }
53 
54     ctx->surface = (*env)->NewGlobalRef(env, surface);
55     if (ctx->surface) {
56         avctx->hwaccel_context = ctx;
57     } else {
58         av_log(avctx, AV_LOG_ERROR, "Could not create new global reference\n");
59         ret = AVERROR_EXTERNAL;
60     }
61 
62     return ret;
63 }
64 
av_mediacodec_default_free(AVCodecContext *avctx)65 void av_mediacodec_default_free(AVCodecContext *avctx)
66 {
67     JNIEnv *env = NULL;
68 
69     AVMediaCodecContext *ctx = avctx->hwaccel_context;
70 
71     if (!ctx) {
72         return;
73     }
74 
75     env = ff_jni_get_env(avctx);
76     if (!env) {
77         return;
78     }
79 
80     if (ctx->surface) {
81         (*env)->DeleteGlobalRef(env, ctx->surface);
82         ctx->surface = NULL;
83     }
84 
85     av_freep(&avctx->hwaccel_context);
86 }
87 
av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)88 int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)
89 {
90     MediaCodecDecContext *ctx = buffer->ctx;
91     int released = atomic_fetch_add(&buffer->released, 1);
92 
93     if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) {
94         atomic_fetch_sub(&ctx->hw_buffer_count, 1);
95         av_log(ctx->avctx, AV_LOG_DEBUG,
96                "Releasing output buffer %zd (%p) ts=%"PRId64" with render=%d [%d pending]\n",
97                buffer->index, buffer, buffer->pts, render, atomic_load(&ctx->hw_buffer_count));
98         return ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, render);
99     }
100 
101     return 0;
102 }
103 
av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time)104 int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time)
105 {
106     MediaCodecDecContext *ctx = buffer->ctx;
107     int released = atomic_fetch_add(&buffer->released, 1);
108 
109     if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) {
110         atomic_fetch_sub(&ctx->hw_buffer_count, 1);
111         av_log(ctx->avctx, AV_LOG_DEBUG,
112                "Rendering output buffer %zd (%p) ts=%"PRId64" with time=%"PRId64" [%d pending]\n",
113                buffer->index, buffer, buffer->pts, time, atomic_load(&ctx->hw_buffer_count));
114         return ff_AMediaCodec_releaseOutputBufferAtTime(ctx->codec, buffer->index, time);
115     }
116 
117     return 0;
118 }
119 
120 #else
121 
122 #include <stdlib.h>
123 
av_mediacodec_alloc_context(void)124 AVMediaCodecContext *av_mediacodec_alloc_context(void)
125 {
126     return NULL;
127 }
128 
av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)129 int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)
130 {
131     return AVERROR(ENOSYS);
132 }
133 
av_mediacodec_default_free(AVCodecContext *avctx)134 void av_mediacodec_default_free(AVCodecContext *avctx)
135 {
136 }
137 
av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)138 int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)
139 {
140     return AVERROR(ENOSYS);
141 }
142 
av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time)143 int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time)
144 {
145     return AVERROR(ENOSYS);
146 }
147 
148 #endif
149