Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * H.264 MP4 to Annex B byte stream format filter
  3.  * Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
  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. #include "avcodec.h"
  27.  
  28. typedef struct H264BSFContext {
  29.     uint8_t  length_size;
  30.     uint8_t  first_idr;
  31.     int      extradata_parsed;
  32. } H264BSFContext;
  33.  
  34. static int alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size,
  35.                           const uint8_t *sps_pps, uint32_t sps_pps_size,
  36.                           const uint8_t *in, uint32_t in_size)
  37. {
  38.     uint32_t offset         = *poutbuf_size;
  39.     uint8_t nal_header_size = offset ? 3 : 4;
  40.     void *tmp;
  41.  
  42.     *poutbuf_size += sps_pps_size + in_size + nal_header_size;
  43.     tmp = av_realloc(*poutbuf, *poutbuf_size + FF_INPUT_BUFFER_PADDING_SIZE);
  44.     if (!tmp)
  45.         return AVERROR(ENOMEM);
  46.     *poutbuf = tmp;
  47.     if (sps_pps)
  48.         memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
  49.     memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
  50.     if (!offset) {
  51.         AV_WB32(*poutbuf + sps_pps_size, 1);
  52.     } else {
  53.         (*poutbuf + offset + sps_pps_size)[0] =
  54.         (*poutbuf + offset + sps_pps_size)[1] = 0;
  55.         (*poutbuf + offset + sps_pps_size)[2] = 1;
  56.     }
  57.  
  58.     return 0;
  59. }
  60.  
  61. static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
  62. {
  63.     uint16_t unit_size;
  64.     uint64_t total_size                 = 0;
  65.     uint8_t *out                        = NULL, unit_nb, sps_done = 0,
  66.              sps_seen                   = 0, pps_seen = 0;
  67.     const uint8_t *extradata            = avctx->extradata + 4;
  68.     static const uint8_t nalu_header[4] = { 0, 0, 0, 1 };
  69.     int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size
  70.  
  71.     /* retrieve sps and pps unit(s) */
  72.     unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
  73.     if (!unit_nb) {
  74.         goto pps;
  75.     } else {
  76.         sps_seen = 1;
  77.     }
  78.  
  79.     while (unit_nb--) {
  80.         void *tmp;
  81.  
  82.         unit_size   = AV_RB16(extradata);
  83.         total_size += unit_size + 4;
  84.         if (total_size > INT_MAX - padding) {
  85.             av_log(avctx, AV_LOG_ERROR,
  86.                    "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
  87.             av_free(out);
  88.             return AVERROR(EINVAL);
  89.         }
  90.         if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) {
  91.             av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
  92.                    "corrupted stream or invalid MP4/AVCC bitstream\n");
  93.             av_free(out);
  94.             return AVERROR(EINVAL);
  95.         }
  96.         tmp = av_realloc(out, total_size + padding);
  97.         if (!tmp) {
  98.             av_free(out);
  99.             return AVERROR(ENOMEM);
  100.         }
  101.         out = tmp;
  102.         memcpy(out + total_size - unit_size - 4, nalu_header, 4);
  103.         memcpy(out + total_size - unit_size, extradata + 2, unit_size);
  104.         extradata += 2 + unit_size;
  105. pps:
  106.         if (!unit_nb && !sps_done++) {
  107.             unit_nb = *extradata++; /* number of pps unit(s) */
  108.             if (unit_nb)
  109.                 pps_seen = 1;
  110.         }
  111.     }
  112.  
  113.     if (out)
  114.         memset(out + total_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
  115.  
  116.     if (!sps_seen)
  117.         av_log(avctx, AV_LOG_WARNING,
  118.                "Warning: SPS NALU missing or invalid. "
  119.                "The resulting stream may not play.\n");
  120.  
  121.     if (!pps_seen)
  122.         av_log(avctx, AV_LOG_WARNING,
  123.                "Warning: PPS NALU missing or invalid. "
  124.                "The resulting stream may not play.\n");
  125.  
  126.     av_free(avctx->extradata);
  127.     avctx->extradata      = out;
  128.     avctx->extradata_size = total_size;
  129.  
  130.     return length_size;
  131. }
  132.  
  133. static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
  134.                                    AVCodecContext *avctx, const char *args,
  135.                                    uint8_t **poutbuf, int *poutbuf_size,
  136.                                    const uint8_t *buf, int buf_size,
  137.                                    int keyframe)
  138. {
  139.     H264BSFContext *ctx = bsfc->priv_data;
  140.     int i;
  141.     uint8_t unit_type;
  142.     int32_t nal_size;
  143.     uint32_t cumul_size    = 0;
  144.     const uint8_t *buf_end = buf + buf_size;
  145.     int ret = 0;
  146.  
  147.     /* nothing to filter */
  148.     if (!avctx->extradata || avctx->extradata_size < 6) {
  149.         *poutbuf      = (uint8_t *)buf;
  150.         *poutbuf_size = buf_size;
  151.         return 0;
  152.     }
  153.  
  154.     /* retrieve sps and pps NAL units from extradata */
  155.     if (!ctx->extradata_parsed) {
  156.         ret = h264_extradata_to_annexb(avctx, FF_INPUT_BUFFER_PADDING_SIZE);
  157.         if (ret < 0)
  158.             return ret;
  159.         ctx->length_size      = ret;
  160.         ctx->first_idr        = 1;
  161.         ctx->extradata_parsed = 1;
  162.     }
  163.  
  164.     *poutbuf_size = 0;
  165.     *poutbuf      = NULL;
  166.     do {
  167.         ret= AVERROR(EINVAL);
  168.         if (buf + ctx->length_size > buf_end)
  169.             goto fail;
  170.  
  171.         for (nal_size = 0, i = 0; i<ctx->length_size; i++)
  172.             nal_size = (nal_size << 8) | buf[i];
  173.  
  174.         buf      += ctx->length_size;
  175.         unit_type = *buf & 0x1f;
  176.  
  177.         if (buf + nal_size > buf_end || nal_size < 0)
  178.             goto fail;
  179.  
  180.         /* prepend only to the first type 5 NAL unit of an IDR picture */
  181.         if (ctx->first_idr && unit_type == 5) {
  182.             if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
  183.                                avctx->extradata, avctx->extradata_size,
  184.                                buf, nal_size)) < 0)
  185.                 goto fail;
  186.             ctx->first_idr = 0;
  187.         } else {
  188.             if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
  189.                                NULL, 0, buf, nal_size)) < 0)
  190.                 goto fail;
  191.             if (!ctx->first_idr && unit_type == 1)
  192.                 ctx->first_idr = 1;
  193.         }
  194.  
  195.         buf        += nal_size;
  196.         cumul_size += nal_size + ctx->length_size;
  197.     } while (cumul_size < buf_size);
  198.  
  199.     return 1;
  200.  
  201. fail:
  202.     av_freep(poutbuf);
  203.     *poutbuf_size = 0;
  204.     return ret;
  205. }
  206.  
  207. AVBitStreamFilter ff_h264_mp4toannexb_bsf = {
  208.     .name           = "h264_mp4toannexb",
  209.     .priv_data_size = sizeof(H264BSFContext),
  210.     .filter         = h264_mp4toannexb_filter,
  211. };
  212.