LCOV - code coverage report
Current view: top level - libavcodec - extract_extradata_bsf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 123 155 79.4 %
Date: 2018-05-20 11:54:08 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This file is part of FFmpeg.
       3             :  *
       4             :  * FFmpeg is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Lesser General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2.1 of the License, or (at your option) any later version.
       8             :  *
       9             :  * FFmpeg is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Lesser General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public
      15             :  * License along with FFmpeg; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include <stdint.h>
      20             : 
      21             : #include "libavutil/common.h"
      22             : #include "libavutil/intreadwrite.h"
      23             : #include "libavutil/log.h"
      24             : #include "libavutil/opt.h"
      25             : 
      26             : #include "avcodec.h"
      27             : #include "bsf.h"
      28             : #include "h2645_parse.h"
      29             : #include "h264.h"
      30             : #include "hevc.h"
      31             : #include "vc1_common.h"
      32             : 
      33             : typedef struct ExtractExtradataContext {
      34             :     const AVClass *class;
      35             : 
      36             :     int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
      37             :                    uint8_t **data, int *size);
      38             : 
      39             :     /* H264/HEVC specifc fields */
      40             :     H2645Packet h2645_pkt;
      41             : 
      42             :     /* AVOptions */
      43             :     int remove;
      44             : } ExtractExtradataContext;
      45             : 
      46        4664 : static int val_in_array(const int *arr, int len, int val)
      47             : {
      48             :     int i;
      49       12954 :     for (i = 0; i < len; i++)
      50       10466 :         if (arr[i] == val)
      51        2176 :             return 1;
      52        2488 :     return 0;
      53             : }
      54             : 
      55         449 : static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
      56             :                                    uint8_t **data, int *size)
      57             : {
      58             :     static const int extradata_nal_types_hevc[] = {
      59             :         HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS,
      60             :     };
      61             :     static const int extradata_nal_types_h264[] = {
      62             :         H264_NAL_SPS, H264_NAL_PPS,
      63             :     };
      64             : 
      65         449 :     ExtractExtradataContext *s = ctx->priv_data;
      66             : 
      67         449 :     int extradata_size = 0, filtered_size = 0;
      68             :     const int *extradata_nal_types;
      69             :     int nb_extradata_nal_types;
      70         449 :     int i, has_sps = 0, has_vps = 0, ret = 0;
      71             : 
      72         449 :     if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
      73         208 :         extradata_nal_types    = extradata_nal_types_hevc;
      74         208 :         nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_hevc);
      75             :     } else {
      76         241 :         extradata_nal_types    = extradata_nal_types_h264;
      77         241 :         nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_h264);
      78             :     }
      79             : 
      80         449 :     ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
      81         449 :                                 ctx, 0, 0, ctx->par_in->codec_id, 1);
      82         449 :     if (ret < 0)
      83           0 :         return ret;
      84             : 
      85        2890 :     for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
      86        2441 :         H2645NAL *nal = &s->h2645_pkt.nals[i];
      87        2441 :         if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
      88        1088 :             extradata_size += nal->raw_size + 3;
      89        1088 :             if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
      90         646 :                 if (nal->type == HEVC_NAL_SPS) has_sps = 1;
      91         646 :                 if (nal->type == HEVC_NAL_VPS) has_vps = 1;
      92             :             } else {
      93         442 :                 if (nal->type == H264_NAL_SPS) has_sps = 1;
      94             :             }
      95        1353 :         } else if (s->remove) {
      96           0 :             filtered_size += nal->raw_size + 3;
      97             :         }
      98             :     }
      99             : 
     100         852 :     if (extradata_size &&
     101         806 :         ((ctx->par_in->codec_id == AV_CODEC_ID_HEVC && has_sps && has_vps) ||
     102         434 :          (ctx->par_in->codec_id == AV_CODEC_ID_H264 && has_sps))) {
     103             :         AVBufferRef *filtered_buf;
     104             :         uint8_t *extradata, *filtered_data;
     105             : 
     106         403 :         if (s->remove) {
     107           0 :             filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
     108           0 :             if (!filtered_buf) {
     109           0 :                 return AVERROR(ENOMEM);
     110             :             }
     111           0 :             memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     112             : 
     113           0 :             filtered_data = filtered_buf->data;
     114             :         }
     115             : 
     116         403 :         extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
     117         403 :         if (!extradata) {
     118           0 :             av_buffer_unref(&filtered_buf);
     119           0 :             return AVERROR(ENOMEM);
     120             :         }
     121         403 :         memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     122             : 
     123         403 :         *data = extradata;
     124         403 :         *size = extradata_size;
     125             : 
     126        2626 :         for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
     127        2223 :             H2645NAL *nal = &s->h2645_pkt.nals[i];
     128        2223 :             if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
     129             :                              nal->type)) {
     130        1088 :                 AV_WB24(extradata, 1); // startcode
     131        1088 :                 memcpy(extradata + 3, nal->raw_data, nal->raw_size);
     132        1088 :                 extradata += 3 + nal->raw_size;
     133        1135 :             } else if (s->remove) {
     134           0 :                 AV_WB24(filtered_data, 1); // startcode
     135           0 :                 memcpy(filtered_data + 3, nal->raw_data, nal->raw_size);
     136           0 :                 filtered_data += 3 + nal->raw_size;
     137             :             }
     138             :         }
     139             : 
     140         403 :         if (s->remove) {
     141           0 :             av_buffer_unref(&pkt->buf);
     142           0 :             pkt->buf  = filtered_buf;
     143           0 :             pkt->data = filtered_buf->data;
     144           0 :             pkt->size = filtered_size;
     145             :         }
     146             :     }
     147             : 
     148         449 :     return 0;
     149             : }
     150             : 
     151           6 : static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
     152             :                                  uint8_t **data, int *size)
     153             : {
     154           6 :     ExtractExtradataContext *s = ctx->priv_data;
     155           6 :     const uint8_t *ptr = pkt->data, *end = pkt->data + pkt->size;
     156           6 :     uint32_t state = UINT32_MAX;
     157           6 :     int has_extradata = 0, extradata_size = 0;
     158             : 
     159          29 :     while (ptr < end) {
     160          23 :         ptr = avpriv_find_start_code(ptr, end, &state);
     161          23 :         if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) {
     162          17 :             has_extradata = 1;
     163           6 :         } else if (has_extradata && IS_MARKER(state)) {
     164           6 :             extradata_size = ptr - 4 - pkt->data;
     165           6 :             break;
     166             :         }
     167             :     }
     168             : 
     169           6 :     if (extradata_size) {
     170           6 :         *data = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
     171           6 :         if (!*data)
     172           0 :             return AVERROR(ENOMEM);
     173             : 
     174           6 :         memcpy(*data, pkt->data, extradata_size);
     175           6 :         memset(*data + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     176           6 :         *size = extradata_size;
     177             : 
     178           6 :         if (s->remove) {
     179           0 :             pkt->data += extradata_size;
     180           0 :             pkt->size -= extradata_size;
     181             :         }
     182             :     }
     183             : 
     184           6 :     return 0;
     185             : }
     186             : 
     187         373 : static int extract_extradata_mpeg12(AVBSFContext *ctx, AVPacket *pkt,
     188             :                                      uint8_t **data, int *size)
     189             : {
     190         373 :     ExtractExtradataContext *s = ctx->priv_data;
     191         373 :     uint32_t state = UINT32_MAX;
     192         373 :     int i, found = 0;
     193             : 
     194     2699279 :     for (i = 0; i < pkt->size; i++) {
     195     2699070 :         state = (state << 8) | pkt->data[i];
     196     2699070 :         if (state == 0x1B3)
     197         164 :             found = 1;
     198     2698906 :         else if (found && state != 0x1B5 && state < 0x200 && state >= 0x100) {
     199         164 :             if (i > 3) {
     200         164 :                 *size = i - 3;
     201         164 :                 *data = av_malloc(*size + AV_INPUT_BUFFER_PADDING_SIZE);
     202         164 :                 if (!*data)
     203           0 :                     return AVERROR(ENOMEM);
     204             : 
     205         164 :                 memcpy(*data, pkt->data, *size);
     206         164 :                 memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     207             : 
     208         164 :                 if (s->remove) {
     209           0 :                     pkt->data += *size;
     210           0 :                     pkt->size -= *size;
     211             :                 }
     212             :             }
     213         164 :             break;
     214             :         }
     215             :     }
     216         373 :     return 0;
     217             : }
     218             : 
     219         115 : static int extract_extradata_mpeg4(AVBSFContext *ctx, AVPacket *pkt,
     220             :                                    uint8_t **data, int *size)
     221             : {
     222         115 :     ExtractExtradataContext *s = ctx->priv_data;
     223         115 :     const uint8_t *ptr = pkt->data, *end = pkt->data + pkt->size;
     224         115 :     uint32_t state = UINT32_MAX;
     225             : 
     226         489 :     while (ptr < end) {
     227         374 :         ptr = avpriv_find_start_code(ptr, end, &state);
     228         374 :         if (state == 0x1B3 || state == 0x1B6) {
     229         115 :             if (ptr - pkt->data > 4) {
     230          65 :                 *size = ptr - 4 - pkt->data;
     231          65 :                 *data = av_malloc(*size + AV_INPUT_BUFFER_PADDING_SIZE);
     232          65 :                 if (!*data)
     233           0 :                     return AVERROR(ENOMEM);
     234             : 
     235          65 :                 memcpy(*data, pkt->data, *size);
     236          65 :                 memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     237             : 
     238          65 :                 if (s->remove) {
     239           0 :                     pkt->data += *size;
     240           0 :                     pkt->size -= *size;
     241             :                 }
     242             :             }
     243         115 :             break;
     244             :         }
     245             :     }
     246         115 :     return 0;
     247             : }
     248             : 
     249             : static const struct {
     250             :     enum AVCodecID id;
     251             :     int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
     252             :                    uint8_t **data, int *size);
     253             : } extract_tab[] = {
     254             :     { AV_CODEC_ID_CAVS,       extract_extradata_mpeg4   },
     255             :     { AV_CODEC_ID_H264,       extract_extradata_h2645   },
     256             :     { AV_CODEC_ID_HEVC,       extract_extradata_h2645   },
     257             :     { AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12  },
     258             :     { AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12  },
     259             :     { AV_CODEC_ID_MPEG4,      extract_extradata_mpeg4   },
     260             :     { AV_CODEC_ID_VC1,        extract_extradata_vc1     },
     261             : };
     262             : 
     263         642 : static int extract_extradata_init(AVBSFContext *ctx)
     264             : {
     265         642 :     ExtractExtradataContext *s = ctx->priv_data;
     266             :     int i;
     267             : 
     268        2241 :     for (i = 0; i < FF_ARRAY_ELEMS(extract_tab); i++) {
     269        2241 :         if (extract_tab[i].id == ctx->par_in->codec_id) {
     270         642 :             s->extract = extract_tab[i].extract;
     271         642 :             break;
     272             :         }
     273             :     }
     274         642 :     if (!s->extract)
     275           0 :         return AVERROR_BUG;
     276             : 
     277         642 :     return 0;
     278             : }
     279             : 
     280        1248 : static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *pkt)
     281             : {
     282        1248 :     ExtractExtradataContext *s = ctx->priv_data;
     283        1248 :     uint8_t *extradata = NULL;
     284             :     int extradata_size;
     285        1248 :     int ret = 0;
     286             : 
     287        1248 :     ret = ff_bsf_get_packet_ref(ctx, pkt);
     288        1248 :     if (ret < 0)
     289         305 :         return ret;
     290             : 
     291         943 :     ret = s->extract(ctx, pkt, &extradata, &extradata_size);
     292         943 :     if (ret < 0)
     293           0 :         goto fail;
     294             : 
     295         943 :     if (extradata) {
     296         638 :         ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
     297             :                                       extradata, extradata_size);
     298         638 :         if (ret < 0) {
     299           0 :             av_freep(&extradata);
     300           0 :             goto fail;
     301             :         }
     302             :     }
     303             : 
     304         943 :     return 0;
     305             : 
     306           0 : fail:
     307           0 :     av_packet_unref(pkt);
     308           0 :     return ret;
     309             : }
     310             : 
     311         642 : static void extract_extradata_close(AVBSFContext *ctx)
     312             : {
     313         642 :     ExtractExtradataContext *s = ctx->priv_data;
     314         642 :     ff_h2645_packet_uninit(&s->h2645_pkt);
     315         642 : }
     316             : 
     317             : static const enum AVCodecID codec_ids[] = {
     318             :     AV_CODEC_ID_CAVS,
     319             :     AV_CODEC_ID_H264,
     320             :     AV_CODEC_ID_HEVC,
     321             :     AV_CODEC_ID_MPEG1VIDEO,
     322             :     AV_CODEC_ID_MPEG2VIDEO,
     323             :     AV_CODEC_ID_MPEG4,
     324             :     AV_CODEC_ID_VC1,
     325             :     AV_CODEC_ID_NONE,
     326             : };
     327             : 
     328             : #define OFFSET(x) offsetof(ExtractExtradataContext, x)
     329             : #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
     330             : static const AVOption options[] = {
     331             :     { "remove", "remove the extradata from the bitstream", OFFSET(remove), AV_OPT_TYPE_INT,
     332             :         { .i64 = 0 }, 0, 1, FLAGS },
     333             :     { NULL },
     334             : };
     335             : 
     336             : static const AVClass extract_extradata_class = {
     337             :     .class_name = "extract_extradata",
     338             :     .item_name  = av_default_item_name,
     339             :     .option     = options,
     340             :     .version    = LIBAVUTIL_VERSION_INT,
     341             : };
     342             : 
     343             : const AVBitStreamFilter ff_extract_extradata_bsf = {
     344             :     .name           = "extract_extradata",
     345             :     .codec_ids      = codec_ids,
     346             :     .priv_data_size = sizeof(ExtractExtradataContext),
     347             :     .priv_class     = &extract_extradata_class,
     348             :     .init           = extract_extradata_init,
     349             :     .filter         = extract_extradata_filter,
     350             :     .close          = extract_extradata_close,
     351             : };

Generated by: LCOV version 1.13