* commit '69ab9f53f901eac6a649e22d28cf093357870627':
hevc: split bitstream unescaping to a separate file
Conflicts:
libavcodec/Makefile
libavcodec/hevc.c
See: afa93d198a
Merged-by: Michael Niedermayer <michaelni@gmx.at>
tags/n2.8
| @@ -285,7 +285,7 @@ OBJS-$(CONFIG_HAP_DECODER) += hapdec.o | |||
| OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o | |||
| OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \ | |||
| hevc_cabac.o hevc_refs.o hevcpred.o \ | |||
| hevcdsp.o hevc_filter.o | |||
| hevcdsp.o hevc_filter.o hevc_parse.o | |||
| OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o | |||
| OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ | |||
| canopus.o | |||
| @@ -2786,119 +2786,6 @@ fail: | |||
| return 0; | |||
| } | |||
| /* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication | |||
| * between these functions would be nice. */ | |||
| int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, | |||
| HEVCNAL *nal) | |||
| { | |||
| int i, si, di; | |||
| uint8_t *dst; | |||
| s->skipped_bytes = 0; | |||
| #define STARTCODE_TEST \ | |||
| if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \ | |||
| if (src[i + 2] != 3) { \ | |||
| /* startcode, so we must be past the end */ \ | |||
| length = i; \ | |||
| } \ | |||
| break; \ | |||
| } | |||
| #if HAVE_FAST_UNALIGNED | |||
| #define FIND_FIRST_ZERO \ | |||
| if (i > 0 && !src[i]) \ | |||
| i--; \ | |||
| while (src[i]) \ | |||
| i++ | |||
| #if HAVE_FAST_64BIT | |||
| for (i = 0; i + 1 < length; i += 9) { | |||
| if (!((~AV_RN64A(src + i) & | |||
| (AV_RN64A(src + i) - 0x0100010001000101ULL)) & | |||
| 0x8000800080008080ULL)) | |||
| continue; | |||
| FIND_FIRST_ZERO; | |||
| STARTCODE_TEST; | |||
| i -= 7; | |||
| } | |||
| #else | |||
| for (i = 0; i + 1 < length; i += 5) { | |||
| if (!((~AV_RN32A(src + i) & | |||
| (AV_RN32A(src + i) - 0x01000101U)) & | |||
| 0x80008080U)) | |||
| continue; | |||
| FIND_FIRST_ZERO; | |||
| STARTCODE_TEST; | |||
| i -= 3; | |||
| } | |||
| #endif /* HAVE_FAST_64BIT */ | |||
| #else | |||
| for (i = 0; i + 1 < length; i += 2) { | |||
| if (src[i]) | |||
| continue; | |||
| if (i > 0 && src[i - 1] == 0) | |||
| i--; | |||
| STARTCODE_TEST; | |||
| } | |||
| #endif /* HAVE_FAST_UNALIGNED */ | |||
| if (i >= length - 1) { // no escaped 0 | |||
| nal->data = | |||
| nal->raw_data = src; | |||
| nal->size = | |||
| nal->raw_size = length; | |||
| return length; | |||
| } | |||
| av_fast_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, | |||
| length + FF_INPUT_BUFFER_PADDING_SIZE); | |||
| if (!nal->rbsp_buffer) | |||
| return AVERROR(ENOMEM); | |||
| dst = nal->rbsp_buffer; | |||
| memcpy(dst, src, i); | |||
| si = di = i; | |||
| while (si + 2 < length) { | |||
| // remove escapes (very rare 1:2^22) | |||
| if (src[si + 2] > 3) { | |||
| dst[di++] = src[si++]; | |||
| dst[di++] = src[si++]; | |||
| } else if (src[si] == 0 && src[si + 1] == 0) { | |||
| if (src[si + 2] == 3) { // escape | |||
| dst[di++] = 0; | |||
| dst[di++] = 0; | |||
| si += 3; | |||
| s->skipped_bytes++; | |||
| if (s->skipped_bytes_pos_size < s->skipped_bytes) { | |||
| s->skipped_bytes_pos_size *= 2; | |||
| av_reallocp_array(&s->skipped_bytes_pos, | |||
| s->skipped_bytes_pos_size, | |||
| sizeof(*s->skipped_bytes_pos)); | |||
| if (!s->skipped_bytes_pos) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| if (s->skipped_bytes_pos) | |||
| s->skipped_bytes_pos[s->skipped_bytes-1] = di - 1; | |||
| continue; | |||
| } else // next start code | |||
| goto nsc; | |||
| } | |||
| dst[di++] = src[si++]; | |||
| } | |||
| while (si < length) | |||
| dst[di++] = src[si++]; | |||
| nsc: | |||
| memset(dst + di, 0, FF_INPUT_BUFFER_PADDING_SIZE); | |||
| nal->data = dst; | |||
| nal->size = di; | |||
| nal->raw_data = src; | |||
| nal->raw_size = si; | |||
| return si; | |||
| } | |||
| static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) | |||
| { | |||
| int i, consumed, ret = 0; | |||
| @@ -2982,17 +2869,15 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) | |||
| nal = &s->nals[s->nb_nals]; | |||
| consumed = ff_hevc_extract_rbsp(s, buf, extract_length, nal); | |||
| s->skipped_bytes_nal[s->nb_nals] = s->skipped_bytes; | |||
| s->skipped_bytes_pos_size_nal[s->nb_nals] = s->skipped_bytes_pos_size; | |||
| s->skipped_bytes_pos_nal[s->nb_nals++] = s->skipped_bytes_pos; | |||
| if (consumed < 0) { | |||
| ret = consumed; | |||
| goto fail; | |||
| } | |||
| s->skipped_bytes_nal[s->nb_nals] = s->skipped_bytes; | |||
| s->skipped_bytes_pos_size_nal[s->nb_nals] = s->skipped_bytes_pos_size; | |||
| s->skipped_bytes_pos_nal[s->nb_nals++] = s->skipped_bytes_pos; | |||
| ret = init_get_bits8(&s->HEVClc->gb, nal->data, nal->size); | |||
| if (ret < 0) | |||
| goto fail; | |||
| @@ -944,9 +944,6 @@ int ff_hevc_decode_nal_sps(HEVCContext *s); | |||
| int ff_hevc_decode_nal_pps(HEVCContext *s); | |||
| int ff_hevc_decode_nal_sei(HEVCContext *s); | |||
| int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, | |||
| HEVCNAL *nal); | |||
| /** | |||
| * Mark all frames in DPB as unused for reference. | |||
| */ | |||
| @@ -1051,6 +1048,12 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, | |||
| void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size); | |||
| /** | |||
| * Extract the raw (unescaped) HEVC bitstream. | |||
| */ | |||
| int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, | |||
| HEVCNAL *nal); | |||
| extern const uint8_t ff_hevc_qpel_extra_before[4]; | |||
| extern const uint8_t ff_hevc_qpel_extra_after[4]; | |||
| extern const uint8_t ff_hevc_qpel_extra[4]; | |||
| @@ -0,0 +1,145 @@ | |||
| /* | |||
| * HEVC common code | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg 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. | |||
| * | |||
| * FFmpeg 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 FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/mem.h" | |||
| #include "hevc.h" | |||
| /* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication | |||
| * between these functions would be nice. */ | |||
| int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, | |||
| HEVCNAL *nal) | |||
| { | |||
| int i, si, di; | |||
| uint8_t *dst; | |||
| if (s) | |||
| s->skipped_bytes = 0; | |||
| #define STARTCODE_TEST \ | |||
| if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \ | |||
| if (src[i + 2] != 3) { \ | |||
| /* startcode, so we must be past the end */ \ | |||
| length = i; \ | |||
| } \ | |||
| break; \ | |||
| } | |||
| #if HAVE_FAST_UNALIGNED | |||
| #define FIND_FIRST_ZERO \ | |||
| if (i > 0 && !src[i]) \ | |||
| i--; \ | |||
| while (src[i]) \ | |||
| i++ | |||
| #if HAVE_FAST_64BIT | |||
| for (i = 0; i + 1 < length; i += 9) { | |||
| if (!((~AV_RN64A(src + i) & | |||
| (AV_RN64A(src + i) - 0x0100010001000101ULL)) & | |||
| 0x8000800080008080ULL)) | |||
| continue; | |||
| FIND_FIRST_ZERO; | |||
| STARTCODE_TEST; | |||
| i -= 7; | |||
| } | |||
| #else | |||
| for (i = 0; i + 1 < length; i += 5) { | |||
| if (!((~AV_RN32A(src + i) & | |||
| (AV_RN32A(src + i) - 0x01000101U)) & | |||
| 0x80008080U)) | |||
| continue; | |||
| FIND_FIRST_ZERO; | |||
| STARTCODE_TEST; | |||
| i -= 3; | |||
| } | |||
| #endif /* HAVE_FAST_64BIT */ | |||
| #else | |||
| for (i = 0; i + 1 < length; i += 2) { | |||
| if (src[i]) | |||
| continue; | |||
| if (i > 0 && src[i - 1] == 0) | |||
| i--; | |||
| STARTCODE_TEST; | |||
| } | |||
| #endif /* HAVE_FAST_UNALIGNED */ | |||
| if (i >= length - 1) { // no escaped 0 | |||
| nal->data = | |||
| nal->raw_data = src; | |||
| nal->size = | |||
| nal->raw_size = length; | |||
| return length; | |||
| } | |||
| av_fast_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, | |||
| length + FF_INPUT_BUFFER_PADDING_SIZE); | |||
| if (!nal->rbsp_buffer) | |||
| return AVERROR(ENOMEM); | |||
| dst = nal->rbsp_buffer; | |||
| memcpy(dst, src, i); | |||
| si = di = i; | |||
| while (si + 2 < length) { | |||
| // remove escapes (very rare 1:2^22) | |||
| if (src[si + 2] > 3) { | |||
| dst[di++] = src[si++]; | |||
| dst[di++] = src[si++]; | |||
| } else if (src[si] == 0 && src[si + 1] == 0) { | |||
| if (src[si + 2] == 3) { // escape | |||
| dst[di++] = 0; | |||
| dst[di++] = 0; | |||
| si += 3; | |||
| if (s) { | |||
| s->skipped_bytes++; | |||
| if (s->skipped_bytes_pos_size < s->skipped_bytes) { | |||
| s->skipped_bytes_pos_size *= 2; | |||
| av_reallocp_array(&s->skipped_bytes_pos, | |||
| s->skipped_bytes_pos_size, | |||
| sizeof(*s->skipped_bytes_pos)); | |||
| if (!s->skipped_bytes_pos) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| if (s->skipped_bytes_pos) | |||
| s->skipped_bytes_pos[s->skipped_bytes-1] = di - 1; | |||
| } | |||
| continue; | |||
| } else // next start code | |||
| goto nsc; | |||
| } | |||
| dst[di++] = src[si++]; | |||
| } | |||
| while (si < length) | |||
| dst[di++] = src[si++]; | |||
| nsc: | |||
| memset(dst + di, 0, FF_INPUT_BUFFER_PADDING_SIZE); | |||
| nal->data = dst; | |||
| nal->size = di; | |||
| nal->raw_data = src; | |||
| nal->raw_size = si; | |||
| return si; | |||
| } | |||