vlc | branch: master | Thomas Guillem <tho...@gllm.fr> | Mon Apr 27 09:28:39 2015 +0200| [c3694bf84a4100f6d86daff68dc15e1362329000] | committer: Thomas Guillem
mediacodec: parse SPS/PPS, fix H264 via live streaming Don't abort if H264 fmt doesn't have any valid size or extra. The SPS/PPS will be parsed from DecodeVideo, MediaCodec will be (re)started if video size changes and valid SPS/PPS will be sent via BUFFER_FLAG_CODEC_CONFIG flag. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c3694bf84a4100f6d86daff68dc15e1362329000 --- modules/codec/omxil/android_mediacodec.c | 182 +++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 6 deletions(-) diff --git a/modules/codec/omxil/android_mediacodec.c b/modules/codec/omxil/android_mediacodec.c index 1b0c275..74b28e4 100644 --- a/modules/codec/omxil/android_mediacodec.c +++ b/modules/codec/omxil/android_mediacodec.c @@ -152,10 +152,14 @@ struct decoder_sys_t size_t i_config_buffer; bool b_config_resend; + int i_width; + int i_height; + bool allocated; bool started; bool decoded; bool error_state; + bool b_new_block; ArchitectureSpecificCopyData architecture_specific_data; @@ -395,6 +399,32 @@ end: return ret; } +static int H264GetSPSPPS(uint8_t *p_buf, size_t i_buf, + uint8_t **pp_sps_buf, size_t *p_sps_size, + uint8_t **pp_pps_buf, size_t *p_pps_size, + struct nal_sps *p_sps) +{ + uint8_t *p_sps_buf, *p_pps_buf; + size_t i_sps_size, i_pps_size; + + if (h264_get_spspps(p_buf, i_buf, &p_sps_buf, &i_sps_size, + &p_pps_buf, &i_pps_size) == 0) + { + if (pp_sps_buf && p_sps_size ) + { + *pp_sps_buf = p_sps_buf; + *p_sps_size = i_sps_size; + } + if (pp_pps_buf && p_pps_size ) + { + *pp_pps_buf = p_pps_buf; + *p_pps_size = i_pps_size; + } + return h264_parse_sps(p_sps_buf, i_sps_size, p_sps); + } else + return -1; +} + /***************************************************************************** * OpenMediaCodec: Create the mediacodec instance *****************************************************************************/ @@ -533,10 +563,6 @@ loopclean: p_sys->allocated = true; p_sys->codec = (*env)->NewGlobalRef(env, p_sys->codec); - jobject format = (*env)->CallStaticObjectMethod(env, jfields.media_format_class, - jfields.create_video_format, (*env)->NewStringUTF(env, mime), - p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height); - /* 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 @@ -566,7 +592,32 @@ loopclean: memcpy(p_sys->p_csd0_buffer, p_dec->fmt_in.p_extra, size); } p_sys->i_csd0_buffer = size; + + if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) + { + struct nal_sps sps; + + if (H264GetSPSPPS(p_sys->p_csd0_buffer, p_sys->i_csd0_buffer, + NULL, NULL, NULL, NULL, &sps) == 0) + { + msg_Warn(p_dec, "SPS found, id: %d size: %dx%d (vs %dx%d)", + sps.i_id, sps.i_width, sps.i_height, + p_sys->i_width, p_sys->i_height); + p_sys->i_width = sps.i_width; + p_sys->i_height = sps.i_height; + } + } + } + + if (!p_sys->i_width && !p_sys->i_height) + { + msg_Err(p_dec, "invalid size, abort MediaCodec"); + goto error; } + jobject format = (*env)->CallStaticObjectMethod(env, jfields.media_format_class, + jfields.create_video_format, (*env)->NewStringUTF(env, mime), + p_sys->i_width, p_sys->i_height); + if (p_sys->p_csd0_buffer) { jobject jcsd0_buffer; @@ -742,6 +793,8 @@ static int OpenDecoder(vlc_object_t *p_this) 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: @@ -775,12 +828,24 @@ static int OpenDecoder(vlc_object_t *p_this) p_dec->fmt_out.audio = p_dec->fmt_in.audio; p_dec->b_need_packetized = true; + p_dec->p_sys->i_width = p_dec->fmt_in.video.i_width; + p_dec->p_sys->i_height = p_dec->fmt_in.video.i_height; + p_dec->p_sys->timestamp_fifo = timestamp_FifoNew(32); if (!p_dec->p_sys->timestamp_fifo) goto error; + p_dec->p_sys->b_new_block = true; + switch (p_dec->fmt_in.i_codec) { + case VLC_CODEC_H264: + if (!p_dec->p_sys->i_width || !p_dec->p_sys->i_height) + { + msg_Warn(p_dec, "waiting for sps/pps for codec %4.4s", + (const char *)&p_dec->fmt_in.i_codec); + return VLC_SUCCESS; + } case VLC_CODEC_VC1: if (!p_dec->fmt_in.i_extra) { @@ -1144,6 +1209,101 @@ static int GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t *p_pic, jlong time return 0; } +static bool spsppscmp(decoder_t *p_dec, uint8_t *p_sps_buf, size_t i_sps_size, + uint8_t *p_pps_buf, size_t i_pps_size) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + + if (p_sys->i_config_buffer != i_sps_size + i_pps_size) + return false; + if (p_sps_buf && memcmp(p_sys->p_config_buffer, p_sps_buf, i_sps_size) != 0) + return false; + if (p_pps_buf && memcmp(p_sys->p_config_buffer + i_sps_size, + p_pps_buf, i_pps_size) != 0) + return false; + return true; +} + +static void H264ProcessBlock(decoder_t *p_dec, JNIEnv *env, block_t *p_block, + bool *p_delayed_open) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t *p_sps_buf, *p_pps_buf; + size_t i_sps_size, i_pps_size; + struct nal_sps sps; + struct H264ConvertState convert_state = { 0, 0 }; + + assert(p_dec->fmt_in.i_codec == VLC_CODEC_H264 && p_block); + + if (p_sys->p_csd0_buffer) + { + convert_h264_to_annexb(p_block->p_buffer, p_block->i_buffer, + p_sys->nal_size, &convert_state); + } else if (H264GetSPSPPS(p_block->p_buffer, p_block->i_buffer, + &p_sps_buf, &i_sps_size, + &p_pps_buf, &i_pps_size, &sps) == 0 + && sps.i_width && sps.i_height + && !spsppscmp(p_dec, p_sps_buf, i_sps_size, p_pps_buf, i_pps_size)) + { + void *p_config_buffer; + + msg_Warn(p_dec, "New SPS/PPS found, id: %d size: %dx%d (vs %dx%d) %d %d", + sps.i_id, sps.i_width, sps.i_height, + p_sys->i_width, p_sys->i_height, + i_sps_size, i_pps_size); + + if (p_sys->codec && (sps.i_width != p_sys->i_width || + sps.i_height != p_sys->i_height)) + { + msg_Err(p_dec, "SPS/PPS changed during the stream and " + "MediaCodec configured with a different video size. " + "Restart it !"); + CloseMediaCodec(p_dec, env); + } + if (!p_sys->codec) + *p_delayed_open = true; + + p_config_buffer = realloc(p_sys->p_config_buffer, + i_sps_size + i_pps_size); + if (!p_config_buffer) + free(p_sys->p_config_buffer); + p_sys->p_config_buffer = p_config_buffer; + + if (p_sys->p_config_buffer) + { + if (p_sps_buf && i_sps_size) + memcpy(p_sys->p_config_buffer, p_sps_buf, i_sps_size); + if (p_pps_buf && i_pps_size) + memcpy(p_sys->p_config_buffer + i_sps_size, + p_pps_buf, i_pps_size); + p_sys->i_config_buffer = i_sps_size + i_pps_size; + p_sys->b_config_resend = true; + } + + p_sys->i_width = sps.i_width; + p_sys->i_height = sps.i_height; + } +} + +static void HEVCProcessBlock(decoder_t *p_dec, JNIEnv *env, block_t *p_block, + bool *p_delayed_open) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + struct H264ConvertState convert_state = { 0, 0 }; + + assert(p_dec->fmt_in.i_codec == VLC_CODEC_HEVC && p_block); + + if (p_sys->p_csd0_buffer) + { + convert_h264_to_annexb(p_block->p_buffer, p_block->i_buffer, + p_sys->nal_size, &convert_state); + } + + /* TODO */ + VLC_UNUSED(env); + VLC_UNUSED(p_delayed_open); +} + static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) { decoder_sys_t *p_sys = p_dec->p_sys; @@ -1155,6 +1315,8 @@ 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_new_block = p_block ? p_sys->b_new_block : false; if (p_sys->error_state) goto endclean; @@ -1189,11 +1351,18 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) goto endclean; } + if (b_new_block) + { + p_sys->b_new_block = false; + if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) + H264ProcessBlock(p_dec, env, p_block, &b_delayed_open); + else if (p_dec->fmt_in.i_codec == VLC_CODEC_HEVC) + HEVCProcessBlock(p_dec, env, p_block, &b_delayed_open); + } + /* try delayed opening if there is a new extra data */ if (!p_sys->codec) { - bool b_delayed_open = false; - switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_VC1: @@ -1282,6 +1451,7 @@ endclean: { block_Release(p_block); *pp_block = NULL; + p_sys->b_new_block = true; } if (b_error && !p_sys->error_state) { /* Signal the error to the Java. */ _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits