LCOV - code coverage report
Current view: top level - libavcodec - vp9_superframe_split_bsf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 64 87.5 %
Date: 2017-12-18 20:14:19 Functions: 2 2 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             : /**
      20             :  * @file
      21             :  * This bitstream filter splits VP9 superframes into packets containing
      22             :  * just one frame.
      23             :  */
      24             : 
      25             : #include <stddef.h>
      26             : 
      27             : #include "avcodec.h"
      28             : #include "bsf.h"
      29             : #include "bytestream.h"
      30             : #include "get_bits.h"
      31             : 
      32             : typedef struct VP9SFSplitContext {
      33             :     AVPacket *buffer_pkt;
      34             : 
      35             :     int nb_frames;
      36             :     int next_frame;
      37             :     size_t next_frame_offset;
      38             :     int sizes[8];
      39             : } VP9SFSplitContext;
      40             : 
      41        4490 : static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out)
      42             : {
      43        4490 :     VP9SFSplitContext *s = ctx->priv_data;
      44             :     AVPacket *in;
      45             :     int i, j, ret, marker;
      46        4490 :     int is_superframe = !!s->buffer_pkt;
      47             : 
      48        4490 :     if (!s->buffer_pkt) {
      49        4428 :         ret = ff_bsf_get_packet(ctx, &s->buffer_pkt);
      50        4428 :         if (ret < 0)
      51        2214 :             return ret;
      52        2214 :         in = s->buffer_pkt;
      53             : 
      54        2214 :         marker = in->data[in->size - 1];
      55        2214 :         if ((marker & 0xe0) == 0xc0) {
      56          57 :             int length_size = 1 + ((marker >> 3) & 0x3);
      57          57 :             int   nb_frames = 1 + (marker & 0x7);
      58          57 :             int    idx_size = 2 + nb_frames * length_size;
      59             : 
      60          57 :             if (in->size >= idx_size && in->data[in->size - idx_size] == marker) {
      61             :                 GetByteContext bc;
      62          57 :                 int64_t total_size = 0;
      63             : 
      64          57 :                 bytestream2_init(&bc, in->data + in->size + 1 - idx_size,
      65             :                                  nb_frames * length_size);
      66             : 
      67         176 :                 for (i = 0; i < nb_frames; i++) {
      68         119 :                     int frame_size = 0;
      69         353 :                     for (j = 0; j < length_size; j++)
      70         234 :                         frame_size |= bytestream2_get_byte(&bc) << (j * 8);
      71             : 
      72         119 :                     total_size += frame_size;
      73         119 :                     if (frame_size < 0 || total_size > in->size - idx_size) {
      74           0 :                         av_log(ctx, AV_LOG_ERROR,
      75             :                                "Invalid frame size in a superframe: %d\n", frame_size);
      76           0 :                         ret = AVERROR(EINVAL);
      77           0 :                         goto fail;
      78             :                     }
      79         119 :                     s->sizes[i] = frame_size;
      80             :                 }
      81          57 :                 s->nb_frames         = nb_frames;
      82          57 :                 s->next_frame        = 0;
      83          57 :                 s->next_frame_offset = 0;
      84          57 :                 is_superframe        = 1;
      85             :             }
      86             :         }
      87             :     }
      88             : 
      89        2276 :     if (is_superframe) {
      90             :         GetBitContext gb;
      91         119 :         int profile, invisible = 0;
      92             : 
      93         119 :         ret = av_packet_ref(out, s->buffer_pkt);
      94         119 :         if (ret < 0)
      95           0 :             goto fail;
      96             : 
      97         119 :         out->data += s->next_frame_offset;
      98         119 :         out->size  = s->sizes[s->next_frame];
      99             : 
     100         119 :         s->next_frame_offset += out->size;
     101         119 :         s->next_frame++;
     102             : 
     103         119 :         if (s->next_frame >= s->nb_frames)
     104          57 :             av_packet_free(&s->buffer_pkt);
     105             : 
     106         119 :         ret = init_get_bits8(&gb, out->data, out->size);
     107         119 :         if (ret < 0)
     108           0 :             goto fail;
     109             : 
     110         119 :         get_bits(&gb, 2); // frame_marker
     111         119 :         profile  = get_bits1(&gb);
     112         119 :         profile |= get_bits1(&gb) << 1;
     113         119 :         if (profile == 3)
     114          26 :             get_bits1(&gb);
     115         119 :         if (!get_bits1(&gb)) {
     116         117 :             get_bits1(&gb);
     117         117 :             invisible = !get_bits1(&gb);
     118             :         }
     119             : 
     120         119 :         if (invisible)
     121          62 :             out->pts = AV_NOPTS_VALUE;
     122             : 
     123             :     } else {
     124        2157 :         av_packet_move_ref(out, s->buffer_pkt);
     125        2157 :         av_packet_free(&s->buffer_pkt);
     126             :     }
     127             : 
     128        2276 :     return 0;
     129           0 : fail:
     130           0 :     av_packet_free(&s->buffer_pkt);
     131           0 :     return ret;
     132             : }
     133             : 
     134         451 : static void vp9_superframe_split_uninit(AVBSFContext *ctx)
     135             : {
     136         451 :     VP9SFSplitContext *s = ctx->priv_data;
     137         451 :     av_packet_free(&s->buffer_pkt);
     138         451 : }
     139             : 
     140             : const AVBitStreamFilter ff_vp9_superframe_split_bsf = {
     141             :     .name = "vp9_superframe_split",
     142             :     .priv_data_size = sizeof(VP9SFSplitContext),
     143             :     .close          = vp9_superframe_split_uninit,
     144             :     .filter         = vp9_superframe_split_filter,
     145             :     .codec_ids      = (const enum AVCodecID []){ AV_CODEC_ID_VP9, AV_CODEC_ID_NONE },
     146             : };

Generated by: LCOV version 1.13