LCOV - code coverage report
Current view: top level - libavcodec - dirac_parser.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 127 90.6 %
Date: 2017-12-17 04:34:43 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Dirac parser
       3             :  *
       4             :  * Copyright (c) 2007-2008 Marco Gerards <marco@gnu.org>
       5             :  * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju@gmail.com>
       6             :  *
       7             :  * This file is part of FFmpeg.
       8             :  *
       9             :  * FFmpeg is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public
      11             :  * License as published by the Free Software Foundation; either
      12             :  * version 2.1 of the License, or (at your option) any later version.
      13             :  *
      14             :  * FFmpeg is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public
      20             :  * License along with FFmpeg; if not, write to the Free Software
      21             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      22             :  */
      23             : 
      24             : /**
      25             :  * @file
      26             :  * Dirac Parser
      27             :  * @author Marco Gerards <marco@gnu.org>
      28             :  */
      29             : 
      30             : #include <string.h>
      31             : 
      32             : #include "libavutil/intreadwrite.h"
      33             : #include "libavutil/mem.h"
      34             : 
      35             : #include "parser.h"
      36             : 
      37             : #define DIRAC_PARSE_INFO_PREFIX 0x42424344
      38             : 
      39             : /**
      40             :  * Find the end of the current frame in the bitstream.
      41             :  * @return the position of the first byte of the next frame or -1
      42             :  */
      43             : typedef struct DiracParseContext {
      44             :     int state;
      45             :     int is_synced;
      46             :     int sync_offset;
      47             :     int header_bytes_needed;
      48             :     int overread_index;
      49             :     int buffer_size;
      50             :     int index;
      51             :     uint8_t *buffer;
      52             :     int dirac_unit_size;
      53             :     uint8_t *dirac_unit;
      54             : } DiracParseContext;
      55             : 
      56         812 : static int find_frame_end(DiracParseContext *pc,
      57             :                           const uint8_t *buf, int buf_size)
      58             : {
      59         812 :     uint32_t state = pc->state;
      60         812 :     int i = 0;
      61             : 
      62         812 :     if (!pc->is_synced) {
      63           8 :         for (i = 0; i < buf_size; i++) {
      64           8 :             state = (state << 8) | buf[i];
      65           8 :             if (state == DIRAC_PARSE_INFO_PREFIX) {
      66           2 :                 state                   = -1;
      67           2 :                 pc->is_synced           = 1;
      68           2 :                 pc->header_bytes_needed = 9;
      69           2 :                 pc->sync_offset         = i;
      70           2 :                 break;
      71             :             }
      72             :         }
      73             :     }
      74             : 
      75         812 :     if (pc->is_synced) {
      76         812 :         pc->sync_offset = 0;
      77      670134 :         for (; i < buf_size; i++) {
      78      669478 :             if (state == DIRAC_PARSE_INFO_PREFIX) {
      79         156 :                 if ((buf_size - i) >= pc->header_bytes_needed) {
      80         154 :                     pc->state = -1;
      81         154 :                     return i + pc->header_bytes_needed;
      82             :                 } else {
      83           2 :                     pc->header_bytes_needed = 9 - (buf_size - i);
      84           2 :                     break;
      85             :                 }
      86             :             } else
      87      669322 :                 state = (state << 8) | buf[i];
      88             :         }
      89             :     }
      90         658 :     pc->state = state;
      91         658 :     return -1;
      92             : }
      93             : 
      94             : typedef struct DiracParseUnit {
      95             :     int next_pu_offset;
      96             :     int prev_pu_offset;
      97             :     uint8_t pu_type;
      98             : } DiracParseUnit;
      99             : 
     100         308 : static int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc,
     101             :                              int offset)
     102             : {
     103             :     int i;
     104             :     int8_t *start;
     105             :     static const uint8_t valid_pu_types[] = {
     106             :         0x00, 0x10, 0x20, 0x30, 0x08, 0x48, 0xC8, 0xE8, 0x0A, 0x0C, 0x0D, 0x0E,
     107             :         0x4C, 0x09, 0xCC, 0x88, 0xCB
     108             :     };
     109             : 
     110         308 :     if (offset < 0 || pc->index - 13 < offset)
     111           0 :         return 0;
     112             : 
     113         308 :     start = pc->buffer + offset;
     114         308 :     pu->pu_type = start[4];
     115             : 
     116         308 :     pu->next_pu_offset = AV_RB32(start + 5);
     117         308 :     pu->prev_pu_offset = AV_RB32(start + 9);
     118             : 
     119             :     /* Check for valid parse code */
     120        1990 :     for (i = 0; i < 17; i++)
     121        1990 :         if (valid_pu_types[i] == pu->pu_type)
     122         308 :             break;
     123         308 :     if (i == 17)
     124           0 :         return 0;
     125             : 
     126         308 :     if (pu->pu_type == 0x10 && pu->next_pu_offset == 0x00)
     127           2 :         pu->next_pu_offset = 13; /* The length of a parse info header */
     128             : 
     129             :     /* Check if the parse offsets are somewhat sane */
     130         616 :     if ((pu->next_pu_offset && pu->next_pu_offset < 13) ||
     131         614 :         (pu->prev_pu_offset && pu->prev_pu_offset < 13))
     132           0 :         return 0;
     133             : 
     134         308 :     return 1;
     135             : }
     136             : 
     137         812 : static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx,
     138             :                                int next, const uint8_t **buf, int *buf_size)
     139             : {
     140        1624 :     int parse_timing_info = (s->pts == AV_NOPTS_VALUE &&
     141         812 :                              s->dts == AV_NOPTS_VALUE);
     142         812 :     DiracParseContext *pc = s->priv_data;
     143             : 
     144         812 :     if (pc->overread_index) {
     145          60 :         memmove(pc->buffer, pc->buffer + pc->overread_index,
     146          60 :                pc->index - pc->overread_index);
     147          60 :         pc->index         -= pc->overread_index;
     148          60 :         pc->overread_index = 0;
     149          60 :         if (*buf_size == 0 && pc->buffer[4] == 0x10) {
     150           2 :             *buf      = pc->buffer;
     151           2 :             *buf_size = pc->index;
     152           2 :             return 0;
     153             :         }
     154             :     }
     155             : 
     156         810 :     if (next == -1) {
     157             :         /* Found a possible frame start but not a frame end */
     158         656 :         void *new_buffer =
     159         656 :             av_fast_realloc(pc->buffer, &pc->buffer_size,
     160         656 :                             pc->index + (*buf_size - pc->sync_offset));
     161         656 :         if (!new_buffer)
     162           0 :             return AVERROR(ENOMEM);
     163         656 :         pc->buffer = new_buffer;
     164         656 :         memcpy(pc->buffer + pc->index, (*buf + pc->sync_offset),
     165         656 :                *buf_size - pc->sync_offset);
     166         656 :         pc->index += *buf_size - pc->sync_offset;
     167         656 :         return -1;
     168             :     } else {
     169             :         /* Found a possible frame start and a  possible frame end */
     170             :         DiracParseUnit pu1, pu;
     171         154 :         void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size,
     172         154 :                                            pc->index + next);
     173         154 :         if (!new_buffer)
     174          94 :             return AVERROR(ENOMEM);
     175         154 :         pc->buffer = new_buffer;
     176         154 :         memcpy(pc->buffer + pc->index, *buf, next);
     177         154 :         pc->index += next;
     178             : 
     179             :         /* Need to check if we have a valid Parse Unit. We can't go by the
     180             :          * sync pattern 'BBCD' alone because arithmetic coding of the residual
     181             :          * and motion data can cause the pattern triggering a false start of
     182             :          * frame. So check if the previous parse offset of the next parse unit
     183             :          * is equal to the next parse offset of the current parse unit then
     184             :          * we can be pretty sure that we have a valid parse unit */
     185         308 :         if (!unpack_parse_unit(&pu1, pc, pc->index - 13)                     ||
     186         308 :             !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) ||
     187         308 :             pu.next_pu_offset != pu1.prev_pu_offset                          ||
     188         154 :             pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset
     189             :         ) {
     190           0 :             pc->index              -= 9;
     191           0 :             *buf_size               = next - 9;
     192           0 :             pc->header_bytes_needed = 9;
     193           0 :             return -1;
     194             :         }
     195             : 
     196             :         /* All non-frame data must be accompanied by frame data. This is to
     197             :          * ensure that pts is set correctly. So if the current parse unit is
     198             :          * not frame data, wait for frame data to come along */
     199             : 
     200         462 :         pc->dirac_unit = pc->buffer + pc->index - 13 -
     201         308 :                          pu1.prev_pu_offset - pc->dirac_unit_size;
     202             : 
     203         154 :         pc->dirac_unit_size += pu.next_pu_offset;
     204             : 
     205         154 :         if ((pu.pu_type & 0x08) != 0x08) {
     206          94 :             pc->header_bytes_needed = 9;
     207          94 :             *buf_size               = next;
     208          94 :             return -1;
     209             :         }
     210             : 
     211             :         /* Get the picture number to set the pts and dts*/
     212          60 :         if (parse_timing_info && pu1.prev_pu_offset >= 13) {
     213         120 :             uint8_t *cur_pu = pc->buffer +
     214          60 :                               pc->index - 13 - pu1.prev_pu_offset;
     215          60 :             int pts = AV_RB32(cur_pu + 13);
     216          60 :             if (s->last_pts == 0 && s->last_dts == 0)
     217           2 :                 s->dts = pts - 1;
     218             :             else
     219          58 :                 s->dts = s->last_dts + 1;
     220          60 :             s->pts = pts;
     221          60 :             if (!avctx->has_b_frames && (cur_pu[4] & 0x03))
     222           1 :                 avctx->has_b_frames = 1;
     223             :         }
     224          60 :         if (avctx->has_b_frames && s->pts == s->dts)
     225          21 :             s->pict_type = AV_PICTURE_TYPE_B;
     226             : 
     227             :         /* Finally have a complete Dirac data unit */
     228          60 :         *buf      = pc->dirac_unit;
     229          60 :         *buf_size = pc->dirac_unit_size;
     230             : 
     231          60 :         pc->dirac_unit_size     = 0;
     232          60 :         pc->overread_index      = pc->index - 13;
     233          60 :         pc->header_bytes_needed = 9;
     234             :     }
     235          60 :     return next;
     236             : }
     237             : 
     238         812 : static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
     239             :                        const uint8_t **poutbuf, int *poutbuf_size,
     240             :                        const uint8_t *buf, int buf_size)
     241             : {
     242         812 :     DiracParseContext *pc = s->priv_data;
     243             :     int next;
     244             : 
     245         812 :     *poutbuf      = NULL;
     246         812 :     *poutbuf_size = 0;
     247             : 
     248         812 :     if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
     249           0 :         next          = buf_size;
     250           0 :         *poutbuf      = buf;
     251           0 :         *poutbuf_size = buf_size;
     252             :         /* Assume that data has been packetized into an encapsulation unit. */
     253             :     } else {
     254         812 :         next = find_frame_end(pc, buf, buf_size);
     255         812 :         if (!pc->is_synced && next == -1)
     256             :             /* No frame start found yet. So throw away the entire buffer. */
     257           0 :             return buf_size;
     258             : 
     259         812 :         if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0)
     260         750 :             return buf_size;
     261             :     }
     262             : 
     263          62 :     *poutbuf      = buf;
     264          62 :     *poutbuf_size = buf_size;
     265          62 :     return next;
     266             : }
     267             : 
     268          29 : static void dirac_parse_close(AVCodecParserContext *s)
     269             : {
     270          29 :     DiracParseContext *pc = s->priv_data;
     271             : 
     272          29 :     if (pc->buffer_size > 0)
     273           2 :         av_freep(&pc->buffer);
     274          29 : }
     275             : 
     276             : AVCodecParser ff_dirac_parser = {
     277             :     .codec_ids      = { AV_CODEC_ID_DIRAC },
     278             :     .priv_data_size = sizeof(DiracParseContext),
     279             :     .parser_parse   = dirac_parse,
     280             :     .parser_close   = dirac_parse_close,
     281             : };

Generated by: LCOV version 1.13