vlc | branch: master | Thomas Guillem <[email protected]> | Tue Mar 21 10:58:51 2017 +0100| [b6d73612d383b25ab12e2f8aad289d045200281a] | committer: Thomas Guillem
mediacodec/videotoolbox: add hxxx_helper hxxx_helper is a H264/HEVC helper used by mediacodec and videtoolbox. For mediacodec, it's used to convert (and validate) xvcC to AnnexB or used to detect SPS/PPS change when decoding AnnexB. For videotoolbox, it's used to validate avcC or to convert AnnexB to avcC (and detect SPS/PPS change) when decoding AnnexB. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=b6d73612d383b25ab12e2f8aad289d045200281a --- modules/codec/Makefile.am | 12 +- modules/codec/hxxx_helper.c | 548 +++++++++++++++++++++++++++++++++++++++ modules/codec/hxxx_helper.h | 84 ++++++ modules/codec/omxil/mediacodec.c | 342 ++++++++---------------- modules/codec/videotoolbox.m | 138 +++++----- 5 files changed, 806 insertions(+), 318 deletions(-) diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am index cc5c27d..f749853 100644 --- a/modules/codec/Makefile.am +++ b/modules/codec/Makefile.am @@ -315,9 +315,11 @@ liboggspots_plugin_la_LIBADD = $(OGGSPOTS_LIBS) EXTRA_LTLIBRARIES += liboggspots_plugin.la codec_LTLIBRARIES += $(LTLIBoggspots) -libvideotoolbox_plugin_la_SOURCES = video_chroma/copy.c video_chroma/copy.h codec/videotoolbox.m \ - packetizer/h264_nal.c packetizer/h264_nal.h \ - packetizer/hxxx_nal.c packetizer/hxxx_nal.h +libvideotoolbox_plugin_la_SOURCES = video_chroma/copy.c video_chroma/copy.h \ + codec/videotoolbox.m codec/hxxx_helper.c codec/hxxx_helper.h \ + packetizer/hxxx_nal.h packetizer/hxxx_nal.c \ + packetizer/h264_nal.c packetizer/h264_nal.h \ + packetizer/hevc_nal.c packetizer/hevc_nal.h if HAVE_OSX libvideotoolbox_plugin_la_OBJCFLAGS = $(AM_CFLAGS) -mmacosx-version-min=10.8 endif @@ -457,7 +459,9 @@ libmediacodec_plugin_la_SOURCES = codec/omxil/mediacodec.c codec/omxil/mediacode video_chroma/copy.c \ video_output/android/utils.c video_output/android/utils.h \ video_output/android/display.h \ - packetizer/hxxx_nal.h packetizer/h264_nal.c packetizer/h264_nal.h \ + codec/hxxx_helper.c codec/hxxx_helper.h \ + packetizer/hxxx_nal.h packetizer/hxxx_nal.c \ + packetizer/h264_nal.c packetizer/h264_nal.h \ packetizer/hevc_nal.c packetizer/hevc_nal.h codec_LTLIBRARIES += $(LTLIBomxil) $(LTLIBomxil_vout) diff --git a/modules/codec/hxxx_helper.c b/modules/codec/hxxx_helper.c new file mode 100644 index 0000000..d36b1d0 --- /dev/null +++ b/modules/codec/hxxx_helper.c @@ -0,0 +1,548 @@ +/***************************************************************************** + * hxxx_helper.c: AnnexB / avcC helper for dumb decoders + ***************************************************************************** + * Copyright (C) 2017 VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdint.h> +#include <assert.h> + +#include <vlc_common.h> +#include <vlc_bits.h> + +#include "hxxx_helper.h" +#include "../packetizer/hxxx_nal.h" +#include "../packetizer/h264_slice.h" + +void +hxxx_helper_init(struct hxxx_helper *hh, vlc_object_t *p_obj, + vlc_fourcc_t i_codec, bool b_need_xvcC) +{ + assert(i_codec == VLC_CODEC_H264 || i_codec == VLC_CODEC_HEVC); + + memset(hh, 0, sizeof(struct hxxx_helper)); + hh->p_obj = p_obj; + hh->i_codec = i_codec; + switch (i_codec) + { + case VLC_CODEC_H264: + break; + } + hh->b_need_xvcC = b_need_xvcC; +} + +void +hxxx_helper_clean(struct hxxx_helper *hh) +{ + switch (hh->i_codec) + { + case VLC_CODEC_H264: + for (size_t i = 0; i <= H264_SPS_ID_MAX; ++i) + { + struct hxxx_helper_nal *hnal = &hh->h264.sps_list[i]; + if (hnal->b) + { + block_Release(hnal->b); + h264_release_sps(hnal->h264_sps); + } + } + for (size_t i = 0; i <= H264_PPS_ID_MAX; ++i) + { + struct hxxx_helper_nal *hnal = &hh->h264.pps_list[i]; + if (hnal->b) + { + block_Release(hnal->b); + h264_release_pps(hnal->h264_pps); + } + } + break; + case VLC_CODEC_HEVC: + if (hh->hevc.p_annexb_config_nal) + block_Release(hh->hevc.p_annexb_config_nal); + break; + default: + vlc_assert_unreachable(); + } +} + +#define HELPER_FOREACH_NAL(it, p_nal_list, i_nal_count, i_nal_max) \ + for (size_t ii = 0, i_nal_nb = 0; i < i_nal_max && i_nal_count > i_nal_nb; ++ii) \ + if (p_nal_list[ii].b != NULL && (it = &p_nal_list[ii]) && ++i_nal_nb) + +static int +helper_dup_buf(struct hxxx_helper_nal *p_nal, + const uint8_t *p_nal_buf, size_t i_nal_buf) +{ + if (!p_nal->b) + { + p_nal->b = block_Alloc(i_nal_buf); + if (!p_nal->b) + return VLC_ENOMEM; + } + else if (p_nal->b != NULL && i_nal_buf > p_nal->b->i_buffer) + { + block_t *b = block_TryRealloc(p_nal->b, 0, i_nal_buf); + if (b == NULL) + return VLC_ENOMEM; + p_nal->b = b; + } + memcpy(p_nal->b->p_buffer, p_nal_buf, i_nal_buf); + p_nal->b->i_buffer = i_nal_buf; + return VLC_SUCCESS; +} + +static inline const struct hxxx_helper_nal * +helper_search_nal(const struct hxxx_helper_nal *p_nal_list, size_t i_nal_count, + size_t i_nal_max, const void *p_nal_buf, size_t i_nal_buf) +{ + size_t i_nal_nb = 0; + for (size_t i = 0; i < i_nal_max && i_nal_count > i_nal_nb; ++i) + { + const struct hxxx_helper_nal *p_nal = &p_nal_list[i]; + if (p_nal->b == NULL) + continue; + i_nal_nb++; + const int i_diff = i_nal_buf - p_nal->b->i_buffer; + if (i_diff == 0 && memcmp(p_nal_buf, p_nal->b->p_buffer, i_nal_buf) == 0) + return p_nal; + } + return NULL; +} +#define helper_search_sps(hh, p_nal, i_nal) \ + helper_search_nal(hh->h264.sps_list, hh->h264.i_sps_count, \ + H264_SPS_ID_MAX+1, p_nal, i_nal) +#define helper_search_pps(hh, p_nal, i_nal) \ + helper_search_nal(hh->h264.pps_list, hh->h264.i_pps_count, \ + H264_PPS_ID_MAX+1, p_nal, i_nal) + +static inline bool +helper_nal_length_valid(struct hxxx_helper *hh) +{ + return hh->i_nal_length_size == 1 || hh->i_nal_length_size == 2 + || hh->i_nal_length_size == 4; +} + +static int +h264_helper_parse_nal(struct hxxx_helper *hh, const uint8_t *p_buf, size_t i_buf, + bool b_is_xvcC, bool *p_config_changed) +{ + const uint8_t *p_nal; + size_t i_nal; + hxxx_iterator_ctx_t it; + hxxx_iterator_init(&it, p_buf, i_buf, hh->i_nal_length_size); + bool (*pf_iterator)(hxxx_iterator_ctx_t *, const uint8_t **, size_t *) = + b_is_xvcC ? hxxx_iterate_next : hxxx_annexb_iterate_next; + *p_config_changed = false; + + while (pf_iterator(&it, &p_nal, &i_nal)) + { + if (i_nal < 2) + continue; + + const enum h264_nal_unit_type_e i_nal_type = p_nal[0] & 0x1F; + + if (i_nal_type == H264_NAL_SPS) + { + if (helper_search_sps(hh, p_nal, i_nal) != NULL) + continue; + h264_sequence_parameter_set_t *p_sps = + h264_decode_sps(p_nal, i_nal, true); + if (!p_sps) + return VLC_EGENERIC; + + struct hxxx_helper_nal *hnal = &hh->h264.sps_list[p_sps->i_id]; + if (helper_dup_buf(hnal, p_nal, i_nal)) + { + h264_release_sps(p_sps); + return VLC_EGENERIC; + } + if (hnal->h264_sps) + h264_release_sps(hnal->h264_sps); + else + hh->h264.i_sps_count++; + + hnal->h264_sps = p_sps; + *p_config_changed = true; + hh->h264.i_current_sps = p_sps->i_id; +fprintf(stderr, "new SPS parsed: %u\n", p_sps->i_id); + } + else if (i_nal_type == H264_NAL_PPS) + { + if (helper_search_pps(hh, p_nal, i_nal) != NULL) + continue; + h264_picture_parameter_set_t *p_pps = + h264_decode_pps(p_nal, i_nal, true); + if (!p_pps) + return VLC_EGENERIC; + + struct hxxx_helper_nal *hnal = &hh->h264.pps_list[p_pps->i_id]; + + if (helper_dup_buf(hnal, p_nal, i_nal)) + { + h264_release_pps(p_pps); + return VLC_EGENERIC; + } + if (hnal->h264_pps) + h264_release_pps(hnal->h264_pps); + else + hh->h264.i_pps_count++; + + hnal->h264_pps = p_pps; + *p_config_changed = true; +fprintf(stderr, "new PPS parsed: %u\n", p_pps->i_id); + } + else if (i_nal_type <= H264_NAL_SLICE_IDR + && i_nal_type != H264_NAL_UNKNOWN) + { + if (hh->h264.i_sps_count > 1) + { + /* There is more than one SPS. Get the PPS id of the current + * SLICE in order to get the current SPS id */ + + /* Get the PPS id from the slice: inspirated from + * h264_decode_slice() */ + bs_t s; + bs_init(&s, p_nal, i_nal); + bs_skip(&s, 8); + bs_read_ue(&s); + bs_read_ue(&s); + unsigned i_pps_id = bs_read_ue(&s); + if (i_pps_id > H264_PPS_ID_MAX) + return VLC_EGENERIC; + + struct hxxx_helper_nal *hpps = &hh->h264.pps_list[i_pps_id]; + if (hpps->b == NULL) + return VLC_EGENERIC; + + struct hxxx_helper_nal *hsps = + &hh->h264.sps_list[hpps->h264_pps->i_sps_id]; + if (hsps->b == NULL) + return VLC_EGENERIC; + + assert(hpps->h264_pps->i_sps_id == hsps->h264_sps->i_id); + if (hsps->h264_sps->i_id != hh->h264.i_current_sps) + { + hh->h264.i_current_sps = hsps->h264_sps->i_id; + *p_config_changed = true; + } + } + break; /* No need to parse further NAL */ + } + } + return VLC_SUCCESS; +} + +static int +h264_helper_set_extra(struct hxxx_helper *hh, const void *p_extra, + size_t i_extra) +{ + if (i_extra == 0) + { + /* AnnexB case */ + hh->i_nal_length_size = 4; + return VLC_SUCCESS; + } + else if (h264_isavcC(p_extra, i_extra)) + { + bool b_unused; + + hh->i_nal_length_size = (((uint8_t*)p_extra)[4] & 0x03) + 1; + if (!helper_nal_length_valid(hh)) + return VLC_EGENERIC; + hh->b_is_xvcC = true; + + if (hh->b_need_xvcC) + return h264_helper_parse_nal(hh, p_extra, i_extra, true, &b_unused); + + size_t i_buf; + uint8_t *p_buf = h264_avcC_to_AnnexB_NAL(p_extra, i_extra, &i_buf, + NULL); + if (!p_buf) + { + msg_Dbg(hh->p_obj, "h264_avcC_to_AnnexB_NAL failed"); + return VLC_EGENERIC; + } + fprintf(stderr, "got annex b extra: %d (nal: %d)\n", i_buf, hh->i_nal_length_size); + + /* XXX h264_AVC_to_AnnexB() works only with a i_nal_length_size of 4. + * If nal_length_size is smaller than 4, fallback to SW decoding. I + * don't know if it's worth the effort to fix h264_AVC_to_AnnexB() for + * a smaller nal_length_size. Indeed, this case will happen only with + * very small resolutions, where hardware decoders are not that useful. + * -Thomas */ + if (hh->i_nal_length_size != 4) + { + msg_Dbg(hh->p_obj, "nal_length_size is too small"); + free(p_buf); + return VLC_EGENERIC; + } + + int i_ret = h264_helper_parse_nal(hh, p_buf, i_buf, false, &b_unused); + free(p_buf); + return i_ret; + } + else /* Can't handle extra that is not avcC */ + return VLC_EGENERIC; +} + +static int +hevc_helper_set_extra(struct hxxx_helper *hh, const void *p_extra, + size_t i_extra) +{ + if (i_extra == 0) + { + /* AnnexB case */ + hh->i_nal_length_size = 4; + return VLC_SUCCESS; + } + else if (hevc_ishvcC(p_extra, i_extra)) + { + hh->i_nal_length_size = hevc_getNALLengthSize(p_extra); + if (!helper_nal_length_valid(hh)) + return VLC_EGENERIC; + hh->b_is_xvcC = true; + + if (hh->b_need_xvcC) + return VLC_SUCCESS; + + size_t i_buf; + uint8_t *p_buf = hevc_hvcC_to_AnnexB_NAL(p_extra, i_extra, &i_buf, + NULL); + if (!p_buf) + { + msg_Dbg(hh->p_obj, "hevc_hvcC_to_AnnexB_NAL failed"); + return VLC_EGENERIC; + } + + hh->hevc.p_annexb_config_nal = p_buf; + hh->hevc.i_annexb_config_nal = i_buf; + return VLC_SUCCESS; + } + else /* Can't handle extra that is not avcC */ + return VLC_EGENERIC; +} + +static block_t * +helper_process_block_xvcc2annexb(struct hxxx_helper *hh, block_t *p_block, + bool *p_config_changed) +{ + assert(helper_nal_length_valid(hh)); + *p_config_changed = false; + h264_AVC_to_AnnexB(p_block->p_buffer, p_block->i_buffer, + hh->i_nal_length_size); + return p_block; +} + +static block_t * +helper_process_block_h264_annexb(struct hxxx_helper *hh, block_t *p_block, + bool *p_config_changed) +{ + int i_ret = h264_helper_parse_nal(hh, p_block->p_buffer, p_block->i_buffer, + false, p_config_changed); + if (i_ret != VLC_SUCCESS) + { + block_Release(p_block); + return NULL; + } + return p_block; +} + +static block_t * +helper_process_block_h264_annexb2avcc(struct hxxx_helper *hh, block_t *p_block, + bool *p_config_changed) +{ + p_block = helper_process_block_h264_annexb(hh, p_block, p_config_changed); + return p_block ? hxxx_AnnexB_to_xVC(p_block, hh->i_nal_length_size) : NULL; +} + +int +hxxx_helper_set_extra(struct hxxx_helper *hh, const void *p_extra, + size_t i_extra) +{ + int i_ret; + switch (hh->i_codec) + { + case VLC_CODEC_H264: + i_ret = h264_helper_set_extra(hh, p_extra, i_extra); + break; + case VLC_CODEC_HEVC: + i_ret = hevc_helper_set_extra(hh, p_extra, i_extra); + break; + default: + vlc_assert_unreachable(); + } + if (i_ret != VLC_SUCCESS) + return i_ret; + + if (hh->b_is_xvcC) + { + if (hh->b_need_xvcC) + hh->pf_process_block = NULL; + else + hh->pf_process_block = helper_process_block_xvcc2annexb; + } + else + { + switch (hh->i_codec) + { + case VLC_CODEC_H264: + if (hh->b_need_xvcC) + hh->pf_process_block = helper_process_block_h264_annexb2avcc; + else + hh->pf_process_block = helper_process_block_h264_annexb; + break; + case VLC_CODEC_HEVC: + if (hh->b_need_xvcC) + return VLC_EGENERIC; /* TODO */ + else + hh->pf_process_block = NULL; + default: + vlc_assert_unreachable(); + } + } + return VLC_SUCCESS;; +} + + +block_t * +h264_helper_get_annexb_config(struct hxxx_helper *hh) +{ + static const uint8_t annexb_startcode[] = { 0x00, 0x00, 0x00, 0x01 }; + + if (hh->h264.i_sps_count == 0 || hh->h264.i_pps_count == 0) + return NULL; + + const struct hxxx_helper_nal *pp_nal_lists[] = { + hh->h264.sps_list, hh->h264.pps_list }; + const size_t p_nal_counts[] = { hh->h264.i_sps_count, hh->h264.i_pps_count }; + const size_t p_nal_maxs[] = { H264_SPS_ID_MAX+1, H264_PPS_ID_MAX+1 }; + + block_t *p_block_list = NULL; + for (size_t i = 0; i < 2; ++i) + { + size_t i_nals_size = 0; + const struct hxxx_helper_nal *p_nal; + HELPER_FOREACH_NAL(p_nal, pp_nal_lists[i], p_nal_counts[i], p_nal_maxs[i]) + { + i_nals_size += p_nal->b->i_buffer + sizeof annexb_startcode; + } + + block_t *p_block = block_Alloc(i_nals_size); + if (p_block == NULL) + { + if (p_block_list != NULL) + block_Release(p_block_list); + return NULL; + } + + p_block->i_buffer = 0; + HELPER_FOREACH_NAL(p_nal, pp_nal_lists[i], p_nal_counts[i], p_nal_maxs[i]) + { + memcpy(&p_block->p_buffer[p_block->i_buffer], annexb_startcode, + sizeof annexb_startcode); + p_block->i_buffer += sizeof annexb_startcode; + memcpy(&p_block->p_buffer[p_block->i_buffer], p_nal->b->p_buffer, + p_nal->b->i_buffer); + p_block->i_buffer += p_nal->b->i_buffer; + } + if (p_block_list == NULL) + p_block_list = p_block; + else + p_block_list->p_next = p_block; + } + + return p_block_list; +} + +block_t * +h264_helper_get_avcc_config(struct hxxx_helper *hh) +{ + const struct hxxx_helper_nal *p_nal; + size_t i = 0; + const uint8_t *pp_sps_bufs[hh->h264.i_sps_count]; + size_t p_sps_sizes[hh->h264.i_sps_count]; + HELPER_FOREACH_NAL(p_nal, hh->h264.sps_list, hh->h264.i_sps_count, + H264_SPS_ID_MAX+1) + { + pp_sps_bufs[i] = p_nal->b->p_buffer; + p_sps_sizes[i] = p_nal->b->i_buffer; + ++i; + } + + i = 0; + const uint8_t *pp_pps_bufs[hh->h264.i_pps_count]; + size_t p_pps_sizes[hh->h264.i_pps_count]; + HELPER_FOREACH_NAL(p_nal, hh->h264.pps_list, hh->h264.i_pps_count, + H264_PPS_ID_MAX+1) + { + pp_pps_bufs[i] = p_nal->b->p_buffer; + p_pps_sizes[i] = p_nal->b->i_buffer; + ++i; + } + return h264_NAL_to_avcC(4, pp_sps_bufs, p_sps_sizes, hh->h264.i_sps_count, + pp_pps_bufs, p_pps_sizes, hh->h264.i_pps_count); +} + +static const struct hxxx_helper_nal * +h264_helper_get_current_sps(struct hxxx_helper *hh) +{ + if (hh->h264.i_sps_count == 0) + return NULL; + + const struct hxxx_helper_nal *hsps = + &hh->h264.sps_list[hh->h264.i_current_sps]; + assert(hsps->b != NULL); + return hsps; +} + +int +h264_helper_get_current_picture_size(struct hxxx_helper *hh, + unsigned *p_w, unsigned *p_h, + unsigned *p_vw, unsigned *p_vh) +{ + const struct hxxx_helper_nal *hsps = h264_helper_get_current_sps(hh); + if (hsps == NULL) + return VLC_EGENERIC; + return h264_get_picture_size(hsps->h264_sps, p_w, p_h, p_vw, p_vh) ? + VLC_SUCCESS : VLC_EGENERIC; +} + +int +h264_helper_get_current_sar(struct hxxx_helper *hh, int *p_num, int *p_den) +{ + const struct hxxx_helper_nal *hsps = h264_helper_get_current_sps(hh); + if (hsps == NULL) + return VLC_EGENERIC; + *p_num = hsps->h264_sps->vui.i_sar_num; + *p_den = hsps->h264_sps->vui.i_sar_den; + return VLC_SUCCESS; +} + +int +h264_helper_get_current_dpb_values(struct hxxx_helper *hh, + uint8_t *p_depth, unsigned *p_delay) +{ + const struct hxxx_helper_nal *hsps = h264_helper_get_current_sps(hh); + if (hsps == NULL) + return VLC_EGENERIC; + return h264_get_dpb_values(hsps->h264_sps, p_depth, p_delay) ? + VLC_SUCCESS : VLC_EGENERIC; +} diff --git a/modules/codec/hxxx_helper.h b/modules/codec/hxxx_helper.h new file mode 100644 index 0000000..a83f455 --- /dev/null +++ b/modules/codec/hxxx_helper.h @@ -0,0 +1,84 @@ +/***************************************************************************** + * hxxx_helper.h: AnnexB / avcC helper for dumb decoders + ***************************************************************************** + * Copyright (C) 2017 VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <vlc_block.h> +#include <vlc_fourcc.h> + +#include "../packetizer/h264_nal.h" +#include "../packetizer/hevc_nal.h" + +struct hxxx_helper_nal +{ + block_t *b; + union { + h264_sequence_parameter_set_t *h264_sps; + h264_picture_parameter_set_t *h264_pps; + }; +}; + +struct hxxx_helper +{ + vlc_object_t *p_obj; /* for logs */ + vlc_fourcc_t i_codec; + bool b_need_xvcC; /* Need avcC or hvcC */ + + bool b_is_xvcC; + uint8_t i_nal_length_size; + union { + struct { + struct hxxx_helper_nal sps_list[H264_SPS_ID_MAX + 1]; + struct hxxx_helper_nal pps_list[H264_PPS_ID_MAX + 1]; + uint8_t i_current_sps; + uint8_t i_sps_count; + uint8_t i_pps_count; + } h264; + struct { + /* TODO: handle VPS/SPS/PPS */ + void *p_annexb_config_nal; + size_t i_annexb_config_nal; + } hevc; + }; + block_t * (*pf_process_block)(struct hxxx_helper *hh, block_t *p_block, + bool *p_config_changed); +}; + +void hxxx_helper_init(struct hxxx_helper *hh, vlc_object_t *p_obj, + vlc_fourcc_t i_codec, bool b_need_xvcC); +void hxxx_helper_clean(struct hxxx_helper *hh); + +int hxxx_helper_set_extra(struct hxxx_helper *hh, const void *p_extra, + size_t i_extra); + +block_t *h264_helper_get_annexb_config(struct hxxx_helper *hh); + +block_t *h264_helper_get_avcc_config(struct hxxx_helper *hh); + +int h264_helper_get_current_picture_size(struct hxxx_helper *hh, + unsigned *p_w, unsigned *p_h, + unsigned *p_vw, unsigned *p_vh); + +int h264_helper_get_current_sar(struct hxxx_helper *hh, int *p_num, int *p_den); + +int h264_helper_get_current_dpb_values(struct hxxx_helper *hh, + uint8_t *p_depth, unsigned *pi_delay); diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c index 3254b62..2ee1293 100644 --- a/modules/codec/omxil/mediacodec.c +++ b/modules/codec/omxil/mediacodec.c @@ -41,9 +41,7 @@ #include <vlc_bits.h> #include "mediacodec.h" -#include "../../packetizer/h264_nal.h" -#include "../../packetizer/hevc_nal.h" -#include "../../packetizer/hxxx_nal.h" +#include "../codec/hxxx_helper.h" #include <OMX_Core.h> #include <OMX_Component.h> #include "omxil_utils.h" @@ -51,13 +49,6 @@ #define BLOCK_FLAG_CSD (0x01 << BLOCK_FLAG_PRIVATE_SHIFT) -/* Codec Specific Data */ -struct csd -{ - const uint8_t *p_buf; - size_t i_size; -}; - #define DECODE_FLAG_RESTART (0x01) #define DECODE_FLASH_FLUSH (0x02) /** @@ -84,7 +75,8 @@ struct decoder_sys_t /* Codec Specific Data buffer: sent in DecodeBlock after a start or a flush * with the BUFFER_FLAG_CODEC_CONFIG flag.*/ - block_t **pp_csd; + #define MAX_CSD_COUNT 3 + block_t *pp_csd[MAX_CSD_COUNT]; size_t i_csd_count; size_t i_csd_send; @@ -121,8 +113,7 @@ struct decoder_sys_t unsigned i_angle; unsigned int i_stride, i_slice_height; int i_pixel_format; - uint8_t i_nal_length_size; - size_t i_h264_profile; + struct hxxx_helper hh; /* stores the inflight picture for each output buffer or NULL */ picture_sys_t** pp_inflight_pictures; unsigned int i_inflight_pictures; @@ -148,8 +139,7 @@ static void CleanDecoder(decoder_t *); static void CloseDecoder(vlc_object_t *); static int Video_OnNewBlock(decoder_t *, block_t **); -static int VideoH264_OnNewBlock(decoder_t *, block_t **); -static int VideoHEVC_OnNewBlock(decoder_t *, block_t **); +static int VideoHXXX_OnNewBlock(decoder_t *, block_t **); static int VideoVC1_OnNewBlock(decoder_t *, block_t **); static void Video_OnFlush(decoder_t *); static int Video_ProcessOutput(decoder_t *, mc_api_out *, picture_t **, @@ -208,204 +198,117 @@ static void CSDFree(decoder_t *p_dec) { decoder_sys_t *p_sys = p_dec->p_sys; - if (p_sys->pp_csd) - { - for (unsigned int i = 0; i < p_sys->i_csd_count; ++i) - block_Release(p_sys->pp_csd[i]); - free(p_sys->pp_csd); - p_sys->pp_csd = NULL; - } + for (unsigned int i = 0; i < p_sys->i_csd_count; ++i) + block_Release(p_sys->pp_csd[i]); p_sys->i_csd_count = 0; } -/* Create the p_sys->p_csd that will be sent from DecodeBlock */ -static int CSDDup(decoder_t *p_dec, const struct csd *p_csd, size_t i_count) +/* Init the p_sys->p_csd that will be sent from DecodeBlock */ +static void CSDInit(decoder_t *p_dec, block_t *p_blocks, size_t i_count) { decoder_sys_t *p_sys = p_dec->p_sys; + assert(i_count >= 0 && i_count <= 3); CSDFree(p_dec); - p_sys->pp_csd = malloc(i_count * sizeof(block_t *)); - if (!p_sys->pp_csd) - return VLC_ENOMEM; - for (size_t i = 0; i < i_count; ++i) { - p_sys->pp_csd[i] = block_Alloc(p_csd[i].i_size); - if (!p_sys->pp_csd[i]) - { - CSDFree(p_dec); - return VLC_ENOMEM; - } + assert(p_blocks != NULL); + p_sys->pp_csd[i] = p_blocks; p_sys->pp_csd[i]->i_flags = BLOCK_FLAG_CSD; - memcpy(p_sys->pp_csd[i]->p_buffer, p_csd[i].p_buf, p_csd[i].i_size); - p_sys->i_csd_count++; + p_blocks = p_blocks->p_next; + p_sys->pp_csd[i]->p_next = NULL; } + p_sys->i_csd_count = i_count; p_sys->i_csd_send = 0; - return VLC_SUCCESS; } -static bool CSDCmp(decoder_t *p_dec, struct csd *p_csd, size_t i_csd_count) +static int CSDDup(decoder_t *p_dec, const void *p_buf, size_t i_buf) { - decoder_sys_t *p_sys = p_dec->p_sys; - - if (p_sys->i_csd_count != i_csd_count) - return false; - for (size_t i = 0; i < i_csd_count; ++i) - { - if (p_sys->pp_csd[i]->i_buffer != p_csd[i].i_size - || memcmp(p_sys->pp_csd[i]->p_buffer, p_csd[i].p_buf, - p_csd[i].i_size) != 0) - return false; - } - return true; -} + block_t *p_block = block_Alloc(i_buf); + if (!p_block) + return VLC_ENOMEM; + memcpy(p_block->p_buffer, p_buf, i_buf); -static inline uint8_t RestoreSyncCode(const uint8_t *p_bufhead, - const uint8_t **pp_buf, size_t *pi_size) -{ - *pp_buf -= 3; - *pi_size += 3; - if (*pp_buf > p_bufhead && (*pp_buf)[-1] == 0) - { - *pp_buf -= 1; - *pi_size += 1; - return 4; - } - return 3; + CSDInit(p_dec, p_block, 1); + return VLC_SUCCESS; } /* Fill the p_sys->p_csd struct with H264 Parameter Sets */ -static int H264SetCSD(decoder_t *p_dec, void *p_buf, size_t i_size, - bool *p_size_changed) +static int H264SetCSD(decoder_t *p_dec, bool *p_size_changed) { - const uint8_t *p_sps_buf = NULL, *p_pps_buf = NULL; - size_t i_sps_size = 0, i_pps_size = 0; - - /* Check if p_buf contains a valid SPS PPS */ - if (h264_AnnexB_get_spspps(p_buf, i_size, - &p_sps_buf, &i_sps_size, - &p_pps_buf, &i_pps_size, - NULL, NULL) && i_sps_size > 0) - { - struct csd csd[2]; - int i_csd_count = 0; - - h264_sequence_parameter_set_t *p_sps - = h264_decode_sps(p_sps_buf, i_sps_size, true); - if (!p_sps) - return VLC_EGENERIC; - - unsigned vsize[4]; - (void) h264_get_picture_size(p_sps, &vsize[0], &vsize[1], &vsize[2], - &vsize[3]); - - if (i_sps_size && RestoreSyncCode(p_buf, &p_sps_buf, &i_sps_size) == 4) - { - csd[i_csd_count].p_buf = p_sps_buf; - csd[i_csd_count].i_size = i_sps_size; - i_csd_count++; - } - if (i_pps_size && RestoreSyncCode(p_buf, &p_pps_buf, &i_pps_size) == 4) - { - csd[i_csd_count].p_buf = p_pps_buf; - csd[i_csd_count].i_size = i_pps_size; - i_csd_count++; - } + decoder_sys_t *p_sys = p_dec->p_sys; + struct hxxx_helper *hh = &p_sys->video.hh; + assert(hh->h264.i_sps_count > 0 || hh->h264.i_pps_count > 0); - /* Compare the SPS PPS with the old one */ - if (!CSDCmp(p_dec, csd, i_csd_count)) - { - msg_Warn(p_dec, "New SPS/PPS found, id: %" PRIu8 " size: %ux%u " - "sps: %d pps: %d", p_sps->i_id, vsize[0], vsize[1], - i_sps_size, i_pps_size); + block_t *p_spspps_blocks = h264_helper_get_annexb_config(hh); - /* In most use cases, p_sys->p_csd[0] contains a SPS, and - * p_sys->p_csd[1] contains a PPS */ - if (CSDDup(p_dec, csd, i_csd_count)) - { - h264_release_sps(p_sps); - return VLC_ENOMEM; - } + if (p_spspps_blocks != NULL) + CSDInit(p_dec, p_spspps_blocks, 2); - if (p_size_changed) - *p_size_changed = (vsize[0] != p_dec->fmt_out.video.i_width - || vsize[1] != p_dec->fmt_out.video.i_height); + unsigned i_w, i_h, i_vw, i_vh; + h264_helper_get_current_picture_size(hh, &i_w, &i_h, &i_vw, &i_vh); - p_dec->fmt_out.video.i_visible_width = - p_dec->fmt_out.video.i_width = vsize[0]; - p_dec->fmt_out.video.i_visible_height = - p_dec->fmt_out.video.i_height = vsize[1]; + if (p_size_changed) + *p_size_changed = (i_w != p_dec->fmt_out.video.i_width + || i_h != p_dec->fmt_out.video.i_height); - h264_release_sps(p_sps); + p_dec->fmt_out.video.i_visible_width = + p_dec->fmt_out.video.i_width = i_w; + p_dec->fmt_out.video.i_visible_height = + p_dec->fmt_out.video.i_height = i_h; + return VLC_SUCCESS; +} - return VLC_SUCCESS; - } +/* Fill the p_sys->p_csd struct with HEVC Parameter Sets */ +static int HEVCSetCSD(decoder_t *p_dec, bool *p_size_changed) +{ + (void) p_size_changed; + decoder_sys_t *p_sys = p_dec->p_sys; + struct hxxx_helper *hh = &p_sys->video.hh; - h264_release_sps(p_sps); - } + assert(hh->hevc.i_annexb_config_nal > 0); - return VLC_EGENERIC; + return CSDDup(p_dec, hh->hevc.p_annexb_config_nal, + hh->hevc.i_annexb_config_nal); } static int ParseVideoExtraH264(decoder_t *p_dec, uint8_t *p_extra, int i_extra) { decoder_sys_t *p_sys = p_dec->p_sys; + struct hxxx_helper *hh = &p_sys->video.hh; - if (h264_isavcC(p_extra, i_extra)) - { - size_t i_size = 0; - uint8_t *p_buf = h264_avcC_to_AnnexB_NAL(p_extra, i_extra, &i_size, - &p_sys->video.i_nal_length_size); - - /* XXX h264_AVC_to_AnnexB() works only with a i_nal_length_size of 4. - * If nal_length_size is smaller than 4, fallback to SW decoding. I - * don't know if it's worth the effort to fix h264_AVC_to_AnnexB() for - * a smaller nal_length_size. Indeed, this case will happen only with - * very small resolutions, where MediaCodec is not that useful. - * -Thomas */ - if (!p_buf || p_sys->video.i_nal_length_size != 4) - { - msg_Dbg(p_dec, "h264_avcC_to_AnnexB_NAL failed%s", - p_buf ? ": nal_length_size too small" : ""); - free(p_buf); - return VLC_EGENERIC; - } - - int i_ret = H264SetCSD(p_dec, p_buf, i_size, NULL); - free(p_buf); + int i_ret = hxxx_helper_set_extra(hh, p_extra, i_extra); + if (i_ret != VLC_SUCCESS) return i_ret; - } - else - return H264SetCSD(p_dec, p_extra, i_extra, NULL); + + assert(hh->pf_process_block != NULL); + + if (hh->h264.i_sps_count > 0 || hh->h264.i_pps_count > 0) + return H264SetCSD(p_dec, NULL); + return VLC_SUCCESS; } static int ParseVideoExtraHEVC(decoder_t *p_dec, uint8_t *p_extra, int i_extra) { decoder_sys_t *p_sys = p_dec->p_sys; + struct hxxx_helper *hh = &p_sys->video.hh; - if (hevc_ishvcC(p_extra, i_extra)) - { - struct csd csd; - uint8_t *p_buf = hevc_hvcC_to_AnnexB_NAL(p_extra, i_extra, &csd.i_size, - &p_sys->video.i_nal_length_size); - if (p_buf) - { - csd.p_buf = p_buf; - CSDDup(p_dec, &csd, 1); - free(p_buf); - } - } - /* FIXME: what to do with AnnexB ? */ + int i_ret = hxxx_helper_set_extra(hh, p_extra, i_extra); + if (i_ret != VLC_SUCCESS || hh->pf_process_block == NULL) + return i_ret; + + assert(hh->pf_process_block != NULL); + if (hh->hevc.i_annexb_config_nal > 0) + return HEVCSetCSD(p_dec, NULL); return VLC_SUCCESS; } static int ParseVideoExtraVc1(decoder_t *p_dec, uint8_t *p_extra, int i_extra) { int offset = 0; - struct csd csd; if (i_extra < 4) return VLC_EGENERIC; @@ -423,10 +326,7 @@ static int ParseVideoExtraVc1(decoder_t *p_dec, uint8_t *p_extra, int i_extra) if (offset >= i_extra - 4) return VLC_EGENERIC; - csd.i_size = i_extra - offset; - csd.p_buf = p_extra + offset; - - return CSDDup(p_dec, &csd, 1); + return CSDDup(p_dec, p_extra + offset, i_extra - offset); } static int ParseVideoExtraWmv3(decoder_t *p_dec, uint8_t *p_extra, int i_extra) @@ -453,17 +353,13 @@ static int ParseVideoExtraWmv3(decoder_t *p_dec, uint8_t *p_extra, int i_extra) 0x00, 0x00, 0x00, 0x00 }; - struct csd csd; - - csd.i_size = sizeof(p_data); /* Adding extradata */ memcpy(&p_data[8], p_extra, 4); /* Adding height and width, little endian */ SetDWLE(&(p_data[12]), p_dec->fmt_in.video.i_height); SetDWLE(&(p_data[16]), p_dec->fmt_in.video.i_width); - csd.p_buf = p_data; - return CSDDup(p_dec, &csd, 1); + return CSDDup(p_dec, p_data, sizeof(p_data)); } static int ParseVideoExtra(decoder_t *p_dec) @@ -545,7 +441,7 @@ static int StartMediaCodec(decoder_t *p_dec) decoder_sys_t *p_sys = p_dec->p_sys; union mc_api_args args; - if (((p_sys->api.i_quirks & MC_API_QUIRKS_NEED_CSD) && !p_sys->pp_csd)) + if (((p_sys->api.i_quirks & MC_API_QUIRKS_NEED_CSD) && !p_sys->i_csd_count)) { msg_Warn(p_dec, "waiting for extra data for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); @@ -564,20 +460,6 @@ static int StartMediaCodec(decoder_t *p_dec) args.video.i_height = p_dec->fmt_out.video.i_height; args.video.i_angle = p_sys->video.i_angle; - /* Configure again if h264 profile changed */ - if (p_dec->fmt_in.i_codec == VLC_CODEC_H264 - && !p_sys->video.i_h264_profile) - { - uint8_t i_profile; - if (h264_get_profile_level(&p_dec->fmt_in, &i_profile, NULL, NULL)) - { - p_sys->video.i_h264_profile = i_profile; - if (p_sys->api.configure(&p_sys->api, - p_sys->video.i_h264_profile) != 0) - return VLC_EGENERIC; - } - } - args.video.p_surface = p_sys->video.p_surface; args.video.p_jsurface = p_sys->video.p_jsurface; args.video.b_tunneled_playback = args.video.p_surface ? @@ -750,10 +632,10 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init) switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_H264: - p_sys->pf_on_new_block = VideoH264_OnNewBlock; - break; case VLC_CODEC_HEVC: - p_sys->pf_on_new_block = VideoHEVC_OnNewBlock; + p_sys->pf_on_new_block = VideoHXXX_OnNewBlock; + hxxx_helper_init(&p_sys->video.hh, VLC_OBJECT(p_dec), + p_dec->fmt_in.i_codec, false); break; case VLC_CODEC_VC1: p_sys->pf_on_new_block = VideoVC1_OnNewBlock; @@ -764,7 +646,6 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init) } p_sys->pf_on_flush = Video_OnFlush; p_sys->pf_process_output = Video_ProcessOutput; - p_sys->video.i_h264_profile = i_h264_profile; p_sys->video.timestamp_fifo = timestamp_FifoNew(32); if (!p_sys->video.timestamp_fifo) @@ -802,23 +683,14 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init) } } - if (p_dec->fmt_in.i_extra) - { - /* Try first to configure specific Video CSD */ - if (p_dec->fmt_in.i_cat == VIDEO_ES) - if (ParseVideoExtra(p_dec) != VLC_SUCCESS) - goto bailout; - - /* Set default CSD if ParseVideoExtra failed to configure one */ - if (!p_sys->pp_csd) - { - struct csd csd; + /* Try first to configure specific Video CSD */ + if (p_dec->fmt_in.i_cat == VIDEO_ES) + if (ParseVideoExtra(p_dec) != VLC_SUCCESS) + goto bailout; - csd.p_buf = p_dec->fmt_in.p_extra; - csd.i_size = p_dec->fmt_in.i_extra; - CSDDup(p_dec, &csd, 1); - } - } + /* Set default CSD if ParseVideoExtra failed to configure one */ + if (!p_sys->i_csd_count && p_dec->fmt_in.i_extra) + CSDDup(p_dec, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra); i_ret = StartMediaCodec(p_dec); switch (i_ret) @@ -889,6 +761,10 @@ static void CleanDecoder(decoder_t *p_dec) if (p_dec->fmt_in.i_cat == VIDEO_ES) { + if (p_dec->fmt_in.i_codec == VLC_CODEC_H264 + || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC) + hxxx_helper_clean(&p_sys->video.hh); + if (p_sys->video.timestamp_fifo) timestamp_FifoRelease(p_sys->video.timestamp_fifo); } @@ -1602,21 +1478,33 @@ static int Video_OnNewBlock(decoder_t *p_dec, block_t **pp_block) return 1; } -static int VideoH264_OnNewBlock(decoder_t *p_dec, block_t **pp_block) +static int VideoHXXX_OnNewBlock(decoder_t *p_dec, block_t **pp_block) { decoder_sys_t *p_sys = p_dec->p_sys; - block_t *p_block = *pp_block; - bool b_size_changed; - - assert(p_dec->fmt_in.i_codec == VLC_CODEC_H264 && p_block); + struct hxxx_helper *hh = &p_sys->video.hh; + bool b_config_changed; - if (p_sys->video.i_nal_length_size) - { - h264_AVC_to_AnnexB(p_block->p_buffer, p_block->i_buffer, - p_sys->video.i_nal_length_size); - } else if (H264SetCSD(p_dec, p_block->p_buffer, p_block->i_buffer, - &b_size_changed) == VLC_SUCCESS) + *pp_block = hh->pf_process_block(hh, *pp_block, &b_config_changed); + if (!*pp_block) + return 0; + if (b_config_changed) { + bool b_size_changed; + int i_ret; + switch (p_dec->fmt_in.i_codec) + { + case VLC_CODEC_H264: + if (hh->h264.i_sps_count > 0 || hh->h264.i_pps_count > 0) + i_ret = H264SetCSD(p_dec, &b_size_changed); + else + i_ret = VLC_EGENERIC; + break; + case VLC_CODEC_HEVC: + i_ret = HEVCSetCSD(p_dec, &b_size_changed); + break; + } + if (i_ret != VLC_SUCCESS) + return i_ret; if (b_size_changed || !p_sys->api.b_started) { if (p_sys->api.b_started) @@ -1626,29 +1514,13 @@ static int VideoH264_OnNewBlock(decoder_t *p_dec, block_t **pp_block) } else { msg_Err(p_dec, "SPS/PPS changed during playback. Flush it"); - p_sys->i_decode_flags |= DECODE_FLASH_FLUSH; + p_sys->i_decode_flags |= DECODE_FLASH_FLUSH; } } return Video_OnNewBlock(p_dec, pp_block); } -static int VideoHEVC_OnNewBlock(decoder_t *p_dec, block_t **pp_block) -{ - decoder_sys_t *p_sys = p_dec->p_sys; - block_t *p_block = *pp_block; - - assert(p_dec->fmt_in.i_codec == VLC_CODEC_HEVC && p_block); - - if (p_sys->video.i_nal_length_size) - { - h264_AVC_to_AnnexB(p_block->p_buffer, p_block->i_buffer, - p_sys->video.i_nal_length_size); - } - - return Video_OnNewBlock(p_dec, pp_block); -} - static int VideoVC1_OnNewBlock(decoder_t *p_dec, block_t **pp_block) { block_t *p_block = *pp_block; diff --git a/modules/codec/videotoolbox.m b/modules/codec/videotoolbox.m index c2de0e7..617433c 100644 --- a/modules/codec/videotoolbox.m +++ b/modules/codec/videotoolbox.m @@ -29,8 +29,7 @@ #import <vlc_common.h> #import <vlc_plugin.h> #import <vlc_codec.h> -#import "../packetizer/h264_nal.h" -#import "../packetizer/hxxx_nal.h" +#import "hxxx_helper.h" #import "../video_chroma/copy.h" #import <vlc_bits.h> #import <vlc_boxes.h> @@ -82,12 +81,13 @@ vlc_module_end() #pragma mark - local prototypes static int ESDSCreate(decoder_t *, uint8_t *, uint32_t); -static int avcCFromAnnexBCreate(decoder_t *, block_t *); +static int avcCFromAnnexBCreate(decoder_t *); static int ExtradataInfoCreate(decoder_t *, CFStringRef, void *, size_t); static int DecodeBlock(decoder_t *, block_t *); static void PicReorder_pushSorted(decoder_t *, picture_t *); static picture_t *PicReorder_pop(decoder_t *, bool); static void PicReorder_flush(decoder_t *); +static void PicReorder_setup(decoder_t *); static void Flush(decoder_t *); static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags, CVPixelBufferRef, CMTime, CMTime); @@ -106,11 +106,10 @@ struct picture_sys_t { struct decoder_sys_t { CMVideoCodecType codec; - uint8_t i_nal_length_size; + struct hxxx_helper hh; bool b_vt_feed; bool b_vt_flush; - bool b_is_avcc; VTDecompressionSessionRef session; CMVideoFormatDescriptionRef videoFormatDescription; CFMutableDictionaryRef decoderConfiguration; @@ -498,24 +497,24 @@ static int SetupDecoderExtradata(decoder_t *p_dec) if (p_sys->codec == kCMVideoCodecType_H264) { + hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec), + p_dec->fmt_in.i_codec, true); + int i_ret = hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra, + p_dec->fmt_in.i_extra); + if (i_ret != VLC_SUCCESS) + return i_ret; + if (p_dec->fmt_in.p_extra) { - if (!h264_isavcC(p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra)) - return VLC_EGENERIC; int i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"), p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra); if (i_ret != VLC_SUCCESS) return i_ret; - p_sys->b_is_avcc = true; - p_sys->i_pic_reorder_max = 5; - } - else - { - /* AnnexB case, we'll get extradata from first input blocks */ - p_sys->b_is_avcc = false; - } + PicReorder_setup(p_dec); + } + /* else: AnnexB case, we'll get extradata from first input blocks */ } else if (p_sys->codec == kCMVideoCodecType_MPEG4Video) { @@ -569,7 +568,6 @@ static int OpenDecoder(vlc_object_t *p_this) p_sys->session = nil; p_sys->b_vt_feed = false; p_sys->b_vt_flush = false; - p_sys->b_is_avcc = false; p_sys->codec = codec; p_sys->videoFormatDescription = nil; p_sys->decoderConfiguration = nil; @@ -737,63 +735,38 @@ static int ESDSCreate(decoder_t *p_dec, uint8_t *p_buf, uint32_t i_buf_size) return i_ret; } -static int avcCFromAnnexBCreate(decoder_t *p_dec, block_t *p_block) +static int avcCFromAnnexBCreate(decoder_t *p_dec) { decoder_sys_t *p_sys = p_dec->p_sys; - /* get the SPS and PPS units from the NAL unit which is either - * part of the demuxer's avvC atom or the mid stream data block */ - const uint8_t *p_sps_nal = NULL, *p_pps_nal = NULL; - size_t i_sps_nalsize = 0, i_pps_nalsize = 0; - if (!h264_AnnexB_get_spspps(p_block->p_buffer, p_block->i_buffer, - &p_sps_nal, &i_sps_nalsize, - &p_pps_nal, &i_pps_nalsize, - NULL, NULL) || i_sps_nalsize == 0) - { - msg_Warn(p_dec, "sps pps detection failed"); + if (p_sys->hh.h264.i_sps_count == 0 || p_sys->hh.h264.i_pps_count == 0) return VLC_EGENERIC; - } - assert(p_sps_nal); - /* Decode Sequence Parameter Set */ - h264_sequence_parameter_set_t *p_sps_data; - if (!(p_sps_data = h264_decode_sps(p_sps_nal, i_sps_nalsize, true))) - { - msg_Warn(p_dec, "sps pps parsing failed"); - return VLC_EGENERIC; - } - - /* this data is more trust-worthy than what we receive - * from the demuxer, so we will use it to over-write - * the current values */ - unsigned h264_width, h264_height, i_video_width, i_video_height; - h264_get_picture_size(p_sps_data, &h264_width, &h264_height, - &i_video_width, &i_video_height); + unsigned i_h264_width, i_h264_height, i_video_width, i_video_height; + int i_sar_num, i_sar_den, i_ret; + i_ret = h264_helper_get_current_picture_size(&p_sys->hh, + &i_h264_width, &i_h264_height, + &i_video_width, &i_video_height); + if (i_ret != VLC_SUCCESS) + return i_ret; + i_ret = h264_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den); + if (i_ret != VLC_SUCCESS) + return i_ret; + PicReorder_setup(p_dec); p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width = i_video_width; p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = i_video_height; - p_dec->fmt_out.video.i_sar_num = p_sps_data->vui.i_sar_num; - p_dec->fmt_out.video.i_sar_den = p_sps_data->vui.i_sar_den; - - uint8_t i_depth; - unsigned i_delay; - if (h264_get_dpb_values(p_sps_data, &i_depth, &i_delay) == false) - i_depth = 4; - p_sys->i_pic_reorder_max = i_depth + 1; - - h264_release_sps(p_sps_data); + p_dec->fmt_out.video.i_sar_num = i_sar_num; + p_dec->fmt_out.video.i_sar_den = i_sar_den; - p_sys->i_nal_length_size = 4; /* default to 4 bytes */ - block_t *p_avcC = h264_NAL_to_avcC(p_sys->i_nal_length_size, - &p_sps_nal, &i_sps_nalsize, 1, - &p_pps_nal, &i_pps_nalsize, 1); + block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh); if (!p_avcC) return VLC_EGENERIC; - int i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"), p_avcC->p_buffer, - p_avcC->i_buffer); + i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"), p_avcC->p_buffer, + p_avcC->i_buffer); block_Release(p_avcC); return i_ret; } @@ -825,17 +798,6 @@ static int ExtradataInfoCreate(decoder_t *p_dec, CFStringRef name, void *p_data, return VLC_SUCCESS; } -static block_t *H264ProcessBlock(decoder_t *p_dec, block_t *p_block) -{ - decoder_sys_t *p_sys = p_dec->p_sys; - assert(p_block); - - if (p_sys->b_is_avcc) /* FIXME: no change checks done for AVC ? */ - return p_block; - - return hxxx_AnnexB_to_xVC(p_block, p_sys->i_nal_length_size); -} - static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec, CMFormatDescriptionRef fmt_desc, block_t *p_block) @@ -973,6 +935,17 @@ static void PicReorder_flush(decoder_t *p_dec) p_sys->p_pic_reorder = NULL; } +static void PicReorder_setup(decoder_t *p_dec) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t i_depth; + unsigned i_delay; + if (h264_helper_get_current_dpb_values(&p_sys->hh, &i_depth, &i_delay) + != VLC_SUCCESS) + i_depth = 4; + p_sys->i_pic_reorder_max = i_depth + 1; +} + static void Flush(decoder_t *p_dec) { decoder_sys_t *p_sys = p_dec->p_sys; @@ -1025,13 +998,26 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block) goto skip; } - if (!p_sys->session) + bool b_config_changed = false; + if (p_sys->codec == kCMVideoCodecType_H264 && p_sys->hh.pf_process_block) + { + p_block = p_sys->hh.pf_process_block(&p_sys->hh, p_block, &b_config_changed); + if (!p_block) + return VLCDEC_SUCCESS; + } + + if (b_config_changed) { /* decoding didn't start yet, which is ok for H264, let's see * if we can use this block to get going */ - assert(p_sys->codec == kCMVideoCodecType_H264 && !p_sys->b_is_avcc); - int i_ret = avcCFromAnnexBCreate(p_dec, p_block); + assert(p_sys->codec == kCMVideoCodecType_H264 && !p_sys->hh.b_is_xvcC); + if (p_sys->session) + { + msg_Dbg(p_dec, "SPS/PPS changed: restarting H264 decoder"); + StopVideoToolbox(p_dec, true); + } + int i_ret = avcCFromAnnexBCreate(p_dec); if (i_ret == VLC_SUCCESS) { if ((p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST @@ -1055,12 +1041,6 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block) goto reload; } - if (p_sys->codec == kCMVideoCodecType_H264) { - p_block = H264ProcessBlock(p_dec, p_block); - if (!p_block) - return VLCDEC_SUCCESS; - } - CMSampleBufferRef sampleBuffer = VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block); if (unlikely(!sampleBuffer)) _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
