[vlc-devel] [PATCH 2/6] mediacodec: Open/Close: separate JNI part from Decoder part
Thomas Guillem
thomas at gllm.fr
Tue May 19 18:58:41 CEST 2015
Rename OpenMediaCodec to StartMediaCodec and CloseMediaCodec to StopMediaCodec.
---
modules/codec/omxil/mediacodec.c | 334 ++++++++++++++++++++-------------------
1 file changed, 173 insertions(+), 161 deletions(-)
diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index af2dfec..cb1500e 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -150,6 +150,7 @@ struct decoder_sys_t
jobject input_buffers, output_buffers;
int pixel_format;
int stride, slice_height;
+ const char *mime;
char *name;
/* Codec Specific Data buffer: sent in PutInput after a start or a flush
@@ -278,7 +279,7 @@ static const struct member members[] = {
*****************************************************************************/
static int OpenDecoder(vlc_object_t *);
static void CloseDecoder(vlc_object_t *);
-static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env);
+static void JniStopMediaCodec(decoder_t *p_dec, JNIEnv *env);
static picture_t *DecodeVideo(decoder_t *, block_t **);
@@ -538,16 +539,13 @@ static int H264SetCSD(decoder_t *p_dec, void *p_buf, size_t i_size,
}
static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
- const char *mime, jstring jmime)
+ const char *mime, jstring jmime,
+ size_t h264_profile)
{
decoder_sys_t *p_sys = p_dec->p_sys;
int num_codecs;
- size_t fmt_profile = 0;
jstring jcodec_name = NULL;
- if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
- h264_get_profile_level(&p_dec->fmt_in, &fmt_profile, NULL, NULL);
-
num_codecs = (*env)->CallStaticIntMethod(env,
jfields.media_codec_list_class,
jfields.get_codec_count);
@@ -600,7 +598,7 @@ static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
/* The mime type is matching for this component. We
now check if the capabilities of the codec is
matching the video format. */
- if (p_dec->fmt_in.i_codec == VLC_CODEC_H264 && fmt_profile) {
+ if (h264_profile) {
/* This decoder doesn't expose its profiles and is high
* profile capable */
if (!strncmp(name_ptr, "OMX.LUMEVideoDecoder", __MIN(20, name_len)))
@@ -612,7 +610,7 @@ static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
int omx_profile = (*env)->GetIntField(env, profile_level, jfields.profile_field);
size_t codec_profile = convert_omx_to_profile_idc(omx_profile);
(*env)->DeleteLocalRef(env, profile_level);
- if (codec_profile != fmt_profile)
+ if (codec_profile != h264_profile)
continue;
/* Some encoders set the level too high, thus we ignore it for the moment.
We could try to guess the actual profile based on the resolution. */
@@ -652,13 +650,11 @@ loopclean:
return jcodec_name;
}
-/*****************************************************************************
- * OpenMediaCodec: Create the mediacodec instance
- *****************************************************************************/
-static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
+static int JniStartMediaCodec(decoder_t *p_dec, JNIEnv *env, jobject jsurface,
+ const char *mime, int i_width, int i_height,
+ size_t h264_profile, int i_angle)
{
decoder_sys_t *p_sys = p_dec->p_sys;
- const char *mime = NULL;
int i_ret = VLC_EGENERIC;
jstring jmime = NULL;
jstring jcodec_name = NULL;
@@ -669,24 +665,11 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
jobject joutput_buffers = NULL;
jobject jbuffer_info = NULL;
- switch (p_dec->fmt_in.i_codec) {
- case VLC_CODEC_HEVC: mime = "video/hevc"; break;
- case VLC_CODEC_H264: mime = "video/avc"; break;
- case VLC_CODEC_H263: mime = "video/3gpp"; break;
- case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break;
- case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break;
- case VLC_CODEC_VC1: mime = "video/wvc1"; break;
- case VLC_CODEC_VP8: mime = "video/x-vnd.on2.vp8"; break;
- case VLC_CODEC_VP9: mime = "video/x-vnd.on2.vp9"; break;
- default:
- vlc_assert_unreachable();
- }
-
jmime = (*env)->NewStringUTF(env, mime);
if (!jmime)
return VLC_EGENERIC;
- jcodec_name = GetMediaCodecName(p_dec, env, mime, jmime);
+ jcodec_name = GetMediaCodecName(p_dec, env, mime, jmime, h264_profile);
if (!jcodec_name) {
msg_Dbg(p_dec, "No suitable codec matching %s was found", mime);
goto error;
@@ -705,122 +688,36 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
p_sys->allocated = true;
p_sys->codec = (*env)->NewGlobalRef(env, jcodec);
- /* Either we use a "csd-0" buffer that is provided before codec
- * initialisation via the MediaFormat class, or use a CODEC_CONFIG buffer
- * that can be provided during playback (and must be provided after a flush
- * and a start). */
- if (p_dec->fmt_in.i_extra && !p_sys->p_csd)
- {
- if (p_dec->fmt_in.i_codec == VLC_CODEC_H264
- || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
- {
- int buf_size = p_dec->fmt_in.i_extra + 20;
- uint32_t size = p_dec->fmt_in.i_extra;
- void *p_buf = malloc(buf_size);
-
- if (!p_buf)
- {
- msg_Warn(p_dec, "extra buffer allocation failed");
- goto error;
- }
-
- if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
- {
- if (((uint8_t*)p_dec->fmt_in.p_extra)[0] == 1
- && convert_sps_pps(p_dec, p_dec->fmt_in.p_extra,
- p_dec->fmt_in.i_extra,
- p_buf, buf_size, &size,
- &p_sys->nal_size) == VLC_SUCCESS)
- H264SetCSD(p_dec, p_buf, size, NULL);
- } else
- {
- if (convert_hevc_nal_units(p_dec, p_dec->fmt_in.p_extra,
- p_dec->fmt_in.i_extra,
- p_buf, buf_size, &size,
- &p_sys->nal_size) == VLC_SUCCESS)
- {
- struct csd csd;
-
- csd.p_buf = p_buf;
- csd.i_size = size;
- CSDDup(p_dec, &csd, 1);
- }
- }
- free(p_buf);
- }
- if (!p_sys->p_csd)
- {
- struct csd csd;
-
- csd.p_buf = p_dec->fmt_in.p_extra;
- csd.i_size = p_dec->fmt_in.i_extra;
- CSDDup(p_dec, &csd, 1);
- }
-
- p_sys->i_csd_send = 0;
- }
-
- if (!p_sys->i_width && !p_sys->i_height)
- {
- msg_Err(p_dec, "invalid size, abort MediaCodec");
- goto error;
- }
jformat = (*env)->CallStaticObjectMethod(env, jfields.media_format_class,
jfields.create_video_format, jmime,
- p_sys->i_width, p_sys->i_height);
+ i_width, i_height);
- p_sys->direct_rendering = var_InheritBool(p_dec, CFG_PREFIX "dr");
+ p_sys->direct_rendering = !!jsurface;
/* There is no way to rotate the video using direct rendering (and using a
* SurfaceView) before API 21 (Lollipop). Therefore, we deactivate direct
* rendering if video doesn't have a normal rotation and if
* get_input_buffer method is not present (This method exists since API
* 21). */
- if (p_sys->direct_rendering
- && p_dec->fmt_in.video.orientation != ORIENT_NORMAL
- && !jfields.get_input_buffer)
+ if (p_sys->direct_rendering && i_angle != 0 && !jfields.get_input_buffer)
p_sys->direct_rendering = false;
if (p_sys->direct_rendering) {
- if (p_dec->fmt_in.video.orientation != ORIENT_NORMAL) {
- int i_angle;
-
- switch (p_dec->fmt_in.video.orientation) {
- case ORIENT_ROTATED_90:
- i_angle = 90;
- break;
- case ORIENT_ROTATED_180:
- i_angle = 180;
- break;
- case ORIENT_ROTATED_270:
- i_angle = 270;
- break;
- default:
- i_angle = 0;
- }
+ if (i_angle != 0)
+ {
jrotation_string = (*env)->NewStringUTF(env, "rotation-degrees");
(*env)->CallVoidMethod(env, jformat, jfields.set_integer,
jrotation_string, i_angle);
}
- jobject surf = jni_LockAndGetAndroidJavaSurface();
- if (surf) {
- // Configure MediaCodec with the Android surface.
- (*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
- jformat, surf, NULL, 0);
- if (CHECK_EXCEPTION()) {
- msg_Warn(p_dec, "Exception occurred in MediaCodec.configure with an output surface.");
- jni_UnlockAndroidSurface();
- goto error;
- }
- p_dec->fmt_out.i_codec = VLC_CODEC_ANDROID_OPAQUE;
- jni_UnlockAndroidSurface();
- } else {
- msg_Warn(p_dec, "Failed to get the Android Surface, disabling direct rendering.");
- p_sys->direct_rendering = false;
+ // Configure MediaCodec with the Android surface.
+ (*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
+ jformat, jsurface, NULL, 0);
+ if (CHECK_EXCEPTION()) {
+ msg_Warn(p_dec, "Exception occurred in MediaCodec.configure with an output surface.");
+ goto error;
}
- }
- if (!p_sys->direct_rendering) {
+ } else {
(*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
jformat, NULL, NULL, 0);
if (CHECK_EXCEPTION()) {
@@ -857,7 +754,6 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
jbuffer_info = (*env)->NewObject(env, jfields.buffer_info_class,
jfields.buffer_info_ctor);
p_sys->buffer_info = (*env)->NewGlobalRef(env, jbuffer_info);
- p_sys->b_update_format = true;
i_ret = VLC_SUCCESS;
@@ -880,30 +776,119 @@ error:
(*env)->DeleteLocalRef(env, jbuffer_info);
if (i_ret != VLC_SUCCESS)
- CloseMediaCodec(p_dec, env);
+ JniStopMediaCodec(p_dec, env);
return i_ret;
}
/*****************************************************************************
- * CloseMediaCodec: Close the mediacodec instance
+ * StartMediaCodec: Create the mediacodec instance
*****************************************************************************/
-static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env)
+static int StartMediaCodec(decoder_t *p_dec, JNIEnv *env)
{
decoder_sys_t *p_sys = p_dec->p_sys;
+ int i_angle = 0, i_ret;
+ size_t h264_profile = 0;
+ jobject jsurface = NULL;
- if (!p_sys)
- return;
+ if (p_dec->fmt_in.i_extra && !p_sys->p_csd)
+ {
+ if (p_dec->fmt_in.i_codec == VLC_CODEC_H264
+ || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
+ {
+ int buf_size = p_dec->fmt_in.i_extra + 20;
+ uint32_t size = p_dec->fmt_in.i_extra;
+ void *p_buf = malloc(buf_size);
- free(p_sys->name);
- p_sys->name = NULL;
+ if (!p_buf)
+ {
+ msg_Warn(p_dec, "extra buffer allocation failed");
+ return VLC_EGENERIC;
+ }
- /* Invalidate all pictures that are currently in flight in order
- * to prevent the vout from using destroyed output buffers. */
- if (p_sys->direct_rendering) {
- InvalidateAllPictures(p_dec);
- p_sys->direct_rendering = false;
+ if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
+ {
+ if (((uint8_t*)p_dec->fmt_in.p_extra)[0] == 1
+ && convert_sps_pps(p_dec, p_dec->fmt_in.p_extra,
+ p_dec->fmt_in.i_extra,
+ p_buf, buf_size, &size,
+ &p_sys->nal_size) == VLC_SUCCESS)
+ H264SetCSD(p_dec, p_buf, size, NULL);
+ } else
+ {
+ if (convert_hevc_nal_units(p_dec, p_dec->fmt_in.p_extra,
+ p_dec->fmt_in.i_extra,
+ p_buf, buf_size, &size,
+ &p_sys->nal_size) == VLC_SUCCESS)
+ {
+ struct csd csd;
+
+ csd.p_buf = p_buf;
+ csd.i_size = size;
+ CSDDup(p_dec, &csd, 1);
+ }
+ }
+ free(p_buf);
+ }
+ if (!p_sys->p_csd)
+ {
+ struct csd csd;
+
+ csd.p_buf = p_dec->fmt_in.p_extra;
+ csd.i_size = p_dec->fmt_in.i_extra;
+ CSDDup(p_dec, &csd, 1);
+ }
+
+ p_sys->i_csd_send = 0;
+ }
+ if (!p_sys->i_width || !p_sys->i_height)
+ {
+ msg_Err(p_dec, "invalid size, abort MediaCodec");
+ return VLC_EGENERIC;
+ }
+
+ if ( p_dec->fmt_in.video.orientation != ORIENT_NORMAL)
+ {
+ switch (p_dec->fmt_in.video.orientation)
+ {
+ case ORIENT_ROTATED_90:
+ i_angle = 90;
+ break;
+ case ORIENT_ROTATED_180:
+ i_angle = 180;
+ break;
+ case ORIENT_ROTATED_270:
+ i_angle = 270;
+ break;
+ default:
+ i_angle = 0;
+ }
}
+ if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
+ h264_get_profile_level(&p_dec->fmt_in, &h264_profile, NULL, NULL);
+
+ if (var_InheritBool(p_dec, CFG_PREFIX "dr"))
+ jsurface = jni_LockAndGetAndroidJavaSurface();
+ i_ret = JniStartMediaCodec(p_dec, env, jsurface, p_sys->mime,
+ p_sys->i_width, p_sys->i_height, h264_profile,
+ i_angle);
+ if (jsurface)
+ jni_UnlockAndroidSurface();
+
+ if (i_ret == VLC_SUCCESS)
+ {
+ if (p_sys->direct_rendering)
+ p_dec->fmt_out.i_codec = VLC_CODEC_ANDROID_OPAQUE;
+ p_sys->b_update_format = true;
+ return VLC_SUCCESS;
+ } else
+ return VLC_EGENERIC;
+}
+
+static void JniStopMediaCodec(decoder_t *p_dec, JNIEnv *env)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
if (p_sys->input_buffers) {
(*env)->DeleteGlobalRef(env, p_sys->input_buffers);
p_sys->input_buffers = NULL;
@@ -937,36 +922,63 @@ static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env)
}
/*****************************************************************************
+ * StopMediaCodec: Close the mediacodec instance
+ *****************************************************************************/
+static void StopMediaCodec(decoder_t *p_dec, JNIEnv *env)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ free(p_sys->name);
+ p_sys->name = NULL;
+
+ /* Invalidate all pictures that are currently in flight in order
+ * to prevent the vout from using destroyed output buffers. */
+ if (p_sys->direct_rendering) {
+ InvalidateAllPictures(p_dec);
+ p_sys->direct_rendering = false;
+ }
+
+ JniStopMediaCodec(p_dec, env);
+}
+
+/*****************************************************************************
* OpenDecoder: Create the decoder instance
*****************************************************************************/
static int OpenDecoder(vlc_object_t *p_this)
{
decoder_t *p_dec = (decoder_t*)p_this;
JNIEnv* env = NULL;
+ const char *mime;
if (p_dec->fmt_in.i_cat != VIDEO_ES && !p_dec->b_force)
return VLC_EGENERIC;
switch (p_dec->fmt_in.i_codec) {
- case VLC_CODEC_H264:
- /* We can handle h264 without a valid video size */
- break;
- case VLC_CODEC_HEVC:
- case VLC_CODEC_H263:
- case VLC_CODEC_MP4V:
- case VLC_CODEC_WMV3:
- case VLC_CODEC_VC1:
- case VLC_CODEC_VP8:
- case VLC_CODEC_VP9:
- if (p_dec->fmt_in.video.i_width && p_dec->fmt_in.video.i_height)
- break;
+ case VLC_CODEC_HEVC: mime = "video/hevc"; break;
+ case VLC_CODEC_H264: mime = "video/avc"; break;
+ case VLC_CODEC_H263: mime = "video/3gpp"; break;
+ case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break;
+ case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break;
+ case VLC_CODEC_VC1: mime = "video/wvc1"; break;
+ case VLC_CODEC_VP8: mime = "video/x-vnd.on2.vp8"; break;
+ case VLC_CODEC_VP9: mime = "video/x-vnd.on2.vp9"; break;
default:
- msg_Dbg(p_dec, "codec %4.4s or resolution (%dx%d) not supported",
- (char *)&p_dec->fmt_in.i_codec,
- p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height);
+ msg_Dbg(p_dec, "codec %4.4s not supported",
+ (char *)&p_dec->fmt_in.i_codec);
return VLC_EGENERIC;
}
+ if (!p_dec->fmt_in.video.i_width || !p_dec->fmt_in.video.i_height)
+ {
+ /* We can handle h264 without a valid video size */
+ if (p_dec->fmt_in.i_codec != VLC_CODEC_H264)
+ {
+ msg_Dbg(p_dec, "resolution (%dx%d) not supported",
+ p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height);
+ return VLC_EGENERIC;
+ }
+ }
+
if (!(env = jni_get_env(THREAD_NAME)))
goto error;
@@ -991,6 +1003,7 @@ static int OpenDecoder(vlc_object_t *p_this)
if (!p_dec->p_sys->timestamp_fifo)
goto error;
+ p_dec->p_sys->mime = mime;
p_dec->p_sys->b_new_block = true;
switch (p_dec->fmt_in.i_codec)
@@ -1011,7 +1024,7 @@ static int OpenDecoder(vlc_object_t *p_this)
}
break;
}
- return OpenMediaCodec(p_dec, env);
+ return StartMediaCodec(p_dec, env);
error:
CloseDecoder(p_this);
@@ -1031,12 +1044,11 @@ static void CloseDecoder(vlc_object_t *p_this)
return;
if ((env = jni_get_env(THREAD_NAME)))
- CloseMediaCodec(p_dec, env);
+ StopMediaCodec(p_dec, env);
else
msg_Warn(p_dec, "Can't get a JNIEnv, can't close mediacodec !");
CSDFree(p_dec);
- free(p_sys->name);
ArchitectureSpecificCopyHooksDestroy(p_sys->pixel_format, &p_sys->architecture_specific_data);
free(p_sys->pp_inflight_pictures);
if (p_sys->timestamp_fifo)
@@ -1422,7 +1434,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
int i_output_ret = 0;
int i_input_ret = 0;
bool b_error = false;
- bool b_delayed_open = false;
+ bool b_delayed_start = false;
bool b_new_block = p_block ? p_sys->b_new_block : false;
if (p_sys->error_state)
@@ -1464,7 +1476,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
{
msg_Err(p_dec, "SPS/PPS changed during playback and "
"video size are different. Restart it !");
- CloseMediaCodec(p_dec, env);
+ StopMediaCodec(p_dec, env);
} else
{
msg_Err(p_dec, "SPS/PPS changed during playback. Flush it");
@@ -1473,7 +1485,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
}
}
if (!p_sys->codec)
- b_delayed_open = true;
+ b_delayed_start = true;
}
/* try delayed opening if there is a new extra data */
@@ -1483,11 +1495,11 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
{
case VLC_CODEC_VC1:
if (p_dec->fmt_in.i_extra)
- b_delayed_open = true;
+ b_delayed_start = true;
default:
break;
}
- if (b_delayed_open && OpenMediaCodec(p_dec, env) != VLC_SUCCESS)
+ if (b_delayed_start && StartMediaCodec(p_dec, env) != VLC_SUCCESS)
{
b_error = true;
goto endclean;
--
2.1.4
More information about the vlc-devel
mailing list