From: Guillaume Martres <[email protected]>

---
 doc/general.texi         |    1 +
 libavcodec/Makefile      |    1 +
 libavcodec/allcodecs.c   |    1 +
 libavcodec/avcodec.h     |    1 +
 libavcodec/hevc_parser.c |  154 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 158 insertions(+)
 create mode 100644 libavcodec/hevc_parser.c

diff --git a/doc/general.texi b/doc/general.texi
index a14e888..836e8c4 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -262,6 +262,7 @@ library:
 @item raw H.261                 @tab X @tab X
 @item raw H.263                 @tab X @tab X
 @item raw H.264                 @tab X @tab X
+@item raw HEVC                  @tab   @tab X
 @item raw Ingenient MJPEG       @tab   @tab X
 @item raw MJPEG                 @tab X @tab X
 @item raw MLP                   @tab   @tab X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 51a45bd..e8fda89 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -624,6 +624,7 @@ OBJS-$(CONFIG_H264_PARSER)             += h264_parser.o 
h264.o            \
                                           h264_refs.o h264_sei.o h264_direct.o 
\
                                           h264_loopfilter.o h264_cabac.o \
                                           h264_cavlc.o h264_ps.o
+OBJS-$(CONFIG_HEVC_PARSER)             += hevc_parser.o
 OBJS-$(CONFIG_AAC_LATM_PARSER)         += latm_parser.o
 OBJS-$(CONFIG_MJPEG_PARSER)            += mjpeg_parser.o
 OBJS-$(CONFIG_MLP_PARSER)              += mlp_parser.o mlp.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 755b4ab..6542b5d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -420,6 +420,7 @@ void avcodec_register_all(void)
     REGISTER_PARSER  (H261, h261);
     REGISTER_PARSER  (H263, h263);
     REGISTER_PARSER  (H264, h264);
+    REGISTER_PARSER  (HEVC, hevc);
     REGISTER_PARSER  (MJPEG, mjpeg);
     REGISTER_PARSER  (MLP, mlp);
     REGISTER_PARSER  (MPEG4VIDEO, mpeg4video);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 9658b67..82bda0c 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -261,6 +261,7 @@ enum AVCodecID {
     AV_CODEC_ID_TSCC2,
     AV_CODEC_ID_MTS2,
     AV_CODEC_ID_CLLC,
+    AV_CODEC_ID_HEVC,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the 
start of audio codecs
diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
new file mode 100644
index 0000000..33fe78d
--- /dev/null
+++ b/libavcodec/hevc_parser.c
@@ -0,0 +1,154 @@
+/*
+ * HEVC Annex B format parser
+ *
+ * Copyright (C) 2012 Guillaume Martres
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/common.h"
+#include "parser.h"
+
+#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
+#define EMULATION_CODE 0x03 ///< emulation_prevention_three_byte
+
+typedef struct HEVCParserContext {
+    ParseContext pc;
+    uint8_t *nal_buffer;
+    unsigned int nal_buffer_size;
+} HEVCParserContext;
+
+/**
+ * Annex B.1: Byte stream NAL unit syntax and semantics
+ */
+static int hevc_parse_nal_unit(HEVCParserContext *hpc, uint8_t **poutbuf,
+                               int *poutbuf_size, const uint8_t *buf,
+                               int buf_size)
+{
+    int i;
+    ParseContext *pc = &hpc->pc;
+    int mask = 0xFFFFFF;
+    int skipped = 0;
+    int header = 0;
+
+    // skip leading zeroes
+    if (!pc->frame_start_found) {
+        for (i = 0; i < buf_size; i++) {
+            pc->state = (pc->state << 8) | buf[i];
+            if ((pc->state & mask) == START_CODE) {
+                pc->frame_start_found = 1;
+                // the frame starts one byte after the start code
+                header = i + 1;
+                break;
+            } else if (buf[i] != 0) {
+                return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    buf      += header;
+    buf_size -= header;
+    *poutbuf = (uint8_t*)buf;
+
+    // Remove emulation bytes and find the frame end
+    if (pc->frame_start_found) {
+        for (i = 0; i < buf_size; i++) {
+            pc->state = (pc->state << 8) | buf[i];
+            switch (pc->state & mask) {
+            case START_CODE:
+                pc->frame_start_found = 0;
+                pc->state = -1;
+                // The start code is three bytes long
+                *poutbuf_size = i - 2 - skipped;
+                return header + i - 2;
+            case EMULATION_CODE:
+                skipped++;
+
+                if (*poutbuf != hpc->nal_buffer) {
+                    hpc->nal_buffer = av_fast_realloc(hpc->nal_buffer,
+                                                      &hpc->nal_buffer_size,
+                                                      buf_size - skipped);
+                    if (!hpc->nal_buffer)
+                        return END_NOT_FOUND;
+                    *poutbuf = hpc->nal_buffer;
+                    memcpy(*poutbuf, buf, i - skipped + 1);
+                }
+                break;
+            default:
+                if (*poutbuf == hpc->nal_buffer)
+                    (*poutbuf)[i-skipped] = buf[i];
+            }
+        }
+    }
+
+    *poutbuf_size = buf_size - skipped;
+    if (buf_size == 0)
+        return 0;
+    return END_NOT_FOUND;
+}
+
+static int hevc_parse(AVCodecParserContext *s,
+                      AVCodecContext *avctx,
+                      const uint8_t **poutbuf, int *poutbuf_size,
+                      const uint8_t *buf, int buf_size)
+{
+    HEVCParserContext *hpc = s->priv_data;
+    ParseContext *pc = &hpc->pc;
+    int combine_next = 0;
+    int next = hevc_parse_nal_unit(hpc, (uint8_t**)poutbuf, poutbuf_size, buf, 
buf_size);
+
+    if (next == AVERROR_INVALIDDATA) {
+        av_log(NULL, AV_LOG_ERROR, "Data fed to parser isn't a NAL unit\n");
+        return next;
+    }
+
+    // next is an offset in buf, but we want to combine frames from *poutbuf
+    combine_next = (next != END_NOT_FOUND) ? *poutbuf_size : next;
+
+    if (ff_combine_frame(pc, combine_next, poutbuf, poutbuf_size) < 0) {
+        *poutbuf      = NULL;
+        *poutbuf_size = 0;
+        return buf_size;
+    }
+
+    return next;
+}
+
+static int hevc_init(AVCodecParserContext *s)
+{
+    HEVCParserContext *hpc = s->priv_data;
+    hpc->nal_buffer_size = 0;
+    hpc->nal_buffer      = NULL;
+    return 0;
+}
+
+static void hevc_close(AVCodecParserContext *s)
+{
+    HEVCParserContext *hpc = s->priv_data;
+    av_free(hpc->nal_buffer);
+
+    ff_parse_close(s);
+}
+
+
+AVCodecParser ff_hevc_parser = {
+    .codec_ids      = { AV_CODEC_ID_HEVC },
+    .priv_data_size = sizeof(HEVCParserContext),
+    .parser_init    = hevc_init,
+    .parser_parse   = hevc_parse,
+    .parser_close   = hevc_close
+};
-- 
1.7.9.5

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to