Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * HEVC MP4 to Annex B byte stream format filter
  3.  * copyright (c) 2015 Anton Khirnov
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. #include <string.h>
  23.  
  24. #include "libavutil/intreadwrite.h"
  25. #include "libavutil/mem.h"
  26.  
  27. #include "avcodec.h"
  28. #include "bytestream.h"
  29. #include "hevc.h"
  30.  
  31. #define MIN_HEVCC_LENGTH 23
  32.  
  33. typedef struct HEVCBSFContext {
  34.     uint8_t  length_size;
  35.     int      extradata_parsed;
  36.  
  37.     int logged_nonmp4_warning;
  38.  
  39.     /* When private_spspps is zero then spspps_buf points to global extradata
  40.        and bsf does replace a global extradata to own-allocated version (default
  41.        behaviour).
  42.        When private_spspps is non-zero the bsf uses a private version of spspps buf.
  43.        This mode necessary when bsf uses in decoder, else bsf has issues after
  44.        decoder re-initialization. Use the "private_spspps_buf" argument to
  45.        activate this mode.
  46.      */
  47.     int      private_spspps;
  48.     uint8_t *spspps_buf;
  49.     uint32_t spspps_size;
  50. } HEVCBSFContext;
  51.  
  52. static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx)
  53. {
  54.     GetByteContext gb;
  55.     int length_size, num_arrays, i, j;
  56.     int ret = 0;
  57.  
  58.     uint8_t *new_extradata = NULL;
  59.     size_t   new_extradata_size = 0;
  60.  
  61.     bytestream2_init(&gb, avctx->extradata, avctx->extradata_size);
  62.  
  63.     bytestream2_skip(&gb, 21);
  64.     length_size = (bytestream2_get_byte(&gb) & 3) + 1;
  65.     num_arrays  = bytestream2_get_byte(&gb);
  66.  
  67.     for (i = 0; i < num_arrays; i++) {
  68.         int type = bytestream2_get_byte(&gb) & 0x3f;
  69.         int cnt  = bytestream2_get_be16(&gb);
  70.  
  71.         if (!(type == NAL_VPS || type == NAL_SPS || type == NAL_PPS ||
  72.               type == NAL_SEI_PREFIX || type == NAL_SEI_SUFFIX)) {
  73.             av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit type in extradata: %d\n",
  74.                    type);
  75.             ret = AVERROR_INVALIDDATA;
  76.             goto fail;
  77.         }
  78.  
  79.         for (j = 0; j < cnt; j++) {
  80.             int nalu_len = bytestream2_get_be16(&gb);
  81.  
  82.             if (4 + AV_INPUT_BUFFER_PADDING_SIZE + nalu_len > SIZE_MAX - new_extradata_size) {
  83.                 ret = AVERROR_INVALIDDATA;
  84.                 goto fail;
  85.             }
  86.             ret = av_reallocp(&new_extradata, new_extradata_size + nalu_len + 4 + AV_INPUT_BUFFER_PADDING_SIZE);
  87.             if (ret < 0)
  88.                 goto fail;
  89.  
  90.             AV_WB32(new_extradata + new_extradata_size, 1); // add the startcode
  91.             bytestream2_get_buffer(&gb, new_extradata + new_extradata_size + 4, nalu_len);
  92.             new_extradata_size += 4 + nalu_len;
  93.             memset(new_extradata + new_extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
  94.         }
  95.     }
  96.  
  97.     if (!ctx->private_spspps) {
  98.         av_freep(&avctx->extradata);
  99.         avctx->extradata      = new_extradata;
  100.         avctx->extradata_size = new_extradata_size;
  101.     }
  102.     ctx->spspps_buf  = new_extradata;
  103.     ctx->spspps_size = new_extradata_size;
  104.  
  105.     if (!new_extradata_size)
  106.         av_log(avctx, AV_LOG_WARNING, "No parameter sets in the extradata\n");
  107.  
  108.     return length_size;
  109. fail:
  110.     av_freep(&new_extradata);
  111.     return ret;
  112. }
  113.  
  114. static int hevc_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
  115.                                    AVCodecContext *avctx, const char *args,
  116.                                    uint8_t **poutbuf, int *poutbuf_size,
  117.                                    const uint8_t *buf, int buf_size,
  118.                                    int keyframe)
  119. {
  120.     HEVCBSFContext *ctx = bsfc->priv_data;
  121.     GetByteContext gb;
  122.  
  123.     uint8_t *out = NULL;
  124.     size_t   out_size = 0;
  125.     int got_irap = 0;
  126.     int i, ret = 0;
  127.  
  128.     if (!ctx->extradata_parsed) {
  129.         if (avctx->extradata_size < MIN_HEVCC_LENGTH ||
  130.             AV_RB24(avctx->extradata) == 1           ||
  131.             AV_RB32(avctx->extradata) == 1) {
  132.             if (!ctx->logged_nonmp4_warning) {
  133.                 av_log(avctx, AV_LOG_VERBOSE,
  134.                        "The input looks like it is Annex B already\n");
  135.                 ctx->logged_nonmp4_warning = 1;
  136.             }
  137.             *poutbuf      = buf;
  138.             *poutbuf_size = buf_size;
  139.             return 0;
  140.         }
  141.         if (args && strstr(args, "private_spspps_buf"))
  142.             ctx->private_spspps = 1;
  143.  
  144.         ret = hevc_extradata_to_annexb(ctx, avctx);
  145.         if (ret < 0)
  146.             return ret;
  147.         ctx->length_size      = ret;
  148.         ctx->extradata_parsed = 1;
  149.     }
  150.  
  151.     *poutbuf_size = 0;
  152.     *poutbuf      = NULL;
  153.  
  154.     bytestream2_init(&gb, buf, buf_size);
  155.  
  156.     while (bytestream2_get_bytes_left(&gb)) {
  157.         uint32_t nalu_size = 0;
  158.         int      nalu_type;
  159.         int is_irap, add_extradata, extra_size;
  160.  
  161.         for (i = 0; i < ctx->length_size; i++)
  162.             nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb);
  163.  
  164.         nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f;
  165.  
  166.         /* prepend extradata to IRAP frames */
  167.         is_irap       = nalu_type >= 16 && nalu_type <= 23;
  168.         add_extradata = is_irap && !got_irap;
  169.         extra_size    = add_extradata * ctx->spspps_size;
  170.         got_irap     |= is_irap;
  171.  
  172.         if (SIZE_MAX - out_size < 4             ||
  173.             SIZE_MAX - out_size - 4 < nalu_size ||
  174.             SIZE_MAX - out_size - 4 - nalu_size < extra_size) {
  175.             ret = AVERROR_INVALIDDATA;
  176.             goto fail;
  177.         }
  178.  
  179.         ret = av_reallocp(&out, out_size + 4 + nalu_size + extra_size);
  180.         if (ret < 0)
  181.             goto fail;
  182.  
  183.         if (add_extradata)
  184.             memcpy(out + out_size, ctx->spspps_buf, extra_size);
  185.         AV_WB32(out + out_size + extra_size, 1);
  186.         bytestream2_get_buffer(&gb, out + out_size + 4 + extra_size, nalu_size);
  187.         out_size += 4 + nalu_size + extra_size;
  188.     }
  189.  
  190.     *poutbuf      = out;
  191.     *poutbuf_size = out_size;
  192.  
  193.     return 1;
  194.  
  195. fail:
  196.     av_freep(&out);
  197.     return ret;
  198. }
  199.  
  200. static void hevc_mp4toannexb_close(AVBitStreamFilterContext *bsfc)
  201. {
  202.     HEVCBSFContext *ctx = bsfc->priv_data;
  203.     if (ctx->private_spspps)
  204.         av_freep(&ctx->spspps_buf);
  205. }
  206.  
  207. AVBitStreamFilter ff_hevc_mp4toannexb_bsf = {
  208.     "hevc_mp4toannexb",
  209.     sizeof(HEVCBSFContext),
  210.     hevc_mp4toannexb_filter,
  211.     hevc_mp4toannexb_close,
  212. };
  213.