LCOV - code coverage report
Current view: top level - libavformat - s337m.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 25 102 24.5 %
Date: 2017-12-15 11:05:35 Functions: 2 5 40.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2017 foo86
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include "libavutil/intreadwrite.h"
      22             : #include "avformat.h"
      23             : #include "spdif.h"
      24             : 
      25             : #define MARKER_16LE         0x72F81F4E
      26             : #define MARKER_20LE         0x20876FF0E154
      27             : #define MARKER_24LE         0x72F8961F4EA5
      28             : 
      29             : #define IS_16LE_MARKER(state)   ((state & 0xFFFFFFFF) == MARKER_16LE)
      30             : #define IS_20LE_MARKER(state)   ((state & 0xF0FFFFF0FFFF) == MARKER_20LE)
      31             : #define IS_24LE_MARKER(state)   ((state & 0xFFFFFFFFFFFF) == MARKER_24LE)
      32             : #define IS_LE_MARKER(state)     (IS_16LE_MARKER(state) || IS_20LE_MARKER(state) || IS_24LE_MARKER(state))
      33             : 
      34           1 : static int s337m_get_offset_and_codec(AVFormatContext *s,
      35             :                                       uint64_t state,
      36             :                                       int data_type, int data_size,
      37             :                                       int *offset, enum AVCodecID *codec)
      38             : {
      39             :     int word_bits;
      40             : 
      41           1 :     if (IS_16LE_MARKER(state)) {
      42           1 :         word_bits = 16;
      43           0 :     } else if (IS_20LE_MARKER(state)) {
      44           0 :         data_type >>= 8;
      45           0 :         data_size >>= 4;
      46           0 :         word_bits = 20;
      47             :     } else {
      48           0 :         data_type >>= 8;
      49           0 :         word_bits = 24;
      50             :     }
      51             : 
      52           1 :     if ((data_type & 0x1F) != 0x1C) {
      53           1 :         if (s)
      54           0 :             avpriv_report_missing_feature(s, "Data type %#x in SMPTE 337M", data_type & 0x1F);
      55           1 :         return AVERROR_PATCHWELCOME;
      56             :     }
      57             : 
      58           0 :     if (codec)
      59           0 :         *codec = AV_CODEC_ID_DOLBY_E;
      60             : 
      61           0 :     switch (data_size / word_bits) {
      62           0 :     case 3648:
      63           0 :         *offset = 1920;
      64           0 :         break;
      65           0 :     case 3644:
      66           0 :         *offset = 2002;
      67           0 :         break;
      68           0 :     case 3640:
      69           0 :         *offset = 2000;
      70           0 :         break;
      71           0 :     case 3040:
      72           0 :         *offset = 1601;
      73           0 :         break;
      74           0 :     default:
      75           0 :         if (s)
      76           0 :             avpriv_report_missing_feature(s, "Dolby E data size %d in SMPTE 337M", data_size);
      77           0 :         return AVERROR_PATCHWELCOME;
      78             :     }
      79             : 
      80           0 :     *offset -= 4;
      81           0 :     *offset *= (word_bits + 7 >> 3) * 2;
      82           0 :     return 0;
      83             : }
      84             : 
      85        6130 : static int s337m_probe(AVProbeData *p)
      86             : {
      87        6130 :     uint64_t state = 0;
      88        6130 :     int markers[3] = { 0 };
      89             :     int i, pos, sum, max, data_type, data_size, offset;
      90             :     uint8_t *buf;
      91             : 
      92   128280795 :     for (pos = 0; pos < p->buf_size; pos++) {
      93   128274665 :         state = (state << 8) | p->buf[pos];
      94   128274665 :         if (!IS_LE_MARKER(state))
      95   128274664 :             continue;
      96             : 
      97           1 :         buf = p->buf + pos + 1;
      98           1 :         if (IS_16LE_MARKER(state)) {
      99           1 :             data_type = AV_RL16(buf    );
     100           1 :             data_size = AV_RL16(buf + 2);
     101             :         } else {
     102           0 :             data_type = AV_RL24(buf    );
     103           0 :             data_size = AV_RL24(buf + 3);
     104             :         }
     105             : 
     106           1 :         if (s337m_get_offset_and_codec(NULL, state, data_type, data_size, &offset, NULL))
     107           1 :             continue;
     108             : 
     109           0 :         i = IS_16LE_MARKER(state) ? 0 : IS_20LE_MARKER(state) ? 1 : 2;
     110           0 :         markers[i]++;
     111             : 
     112           0 :         pos  += IS_16LE_MARKER(state) ? 4 : 6;
     113           0 :         pos  += offset;
     114           0 :         state = 0;
     115             :     }
     116             : 
     117        6130 :     sum = max = 0;
     118       24520 :     for (i = 0; i < FF_ARRAY_ELEMS(markers); i++) {
     119       18390 :         sum += markers[i];
     120       18390 :         if (markers[max] < markers[i])
     121           0 :             max = i;
     122             :     }
     123             : 
     124        6130 :     if (markers[max] > 3 && markers[max] * 4 > sum * 3)
     125           0 :         return AVPROBE_SCORE_EXTENSION + 1;
     126             : 
     127        6130 :     return 0;
     128             : }
     129             : 
     130           0 : static int s337m_read_header(AVFormatContext *s)
     131             : {
     132           0 :     s->ctx_flags |= AVFMTCTX_NOHEADER;
     133           0 :     return 0;
     134             : }
     135             : 
     136           0 : static void bswap_buf24(uint8_t *data, int size)
     137             : {
     138             :     int i;
     139             : 
     140           0 :     for (i = 0; i < size / 3; i++, data += 3)
     141           0 :         FFSWAP(uint8_t, data[0], data[2]);
     142           0 : }
     143             : 
     144           0 : static int s337m_read_packet(AVFormatContext *s, AVPacket *pkt)
     145             : {
     146           0 :     AVIOContext *pb = s->pb;
     147           0 :     uint64_t state = 0;
     148             :     int ret, data_type, data_size, offset;
     149             :     enum AVCodecID codec;
     150             :     int64_t pos;
     151             : 
     152           0 :     while (!IS_LE_MARKER(state)) {
     153           0 :         state = (state << 8) | avio_r8(pb);
     154           0 :         if (avio_feof(pb))
     155           0 :             return AVERROR_EOF;
     156             :     }
     157             : 
     158           0 :     if (IS_16LE_MARKER(state)) {
     159           0 :         data_type = avio_rl16(pb);
     160           0 :         data_size = avio_rl16(pb);
     161             :     } else {
     162           0 :         data_type = avio_rl24(pb);
     163           0 :         data_size = avio_rl24(pb);
     164             :     }
     165             : 
     166           0 :     pos = avio_tell(pb);
     167             : 
     168           0 :     if ((ret = s337m_get_offset_and_codec(s, state, data_type, data_size, &offset, &codec)) < 0)
     169           0 :         return ret;
     170             : 
     171           0 :     if ((ret = av_new_packet(pkt, offset)) < 0)
     172           0 :         return ret;
     173             : 
     174           0 :     pkt->pos = pos;
     175             : 
     176           0 :     if (avio_read(pb, pkt->data, pkt->size) < pkt->size) {
     177           0 :         av_packet_unref(pkt);
     178           0 :         return AVERROR_EOF;
     179             :     }
     180             : 
     181           0 :     if (IS_16LE_MARKER(state))
     182           0 :         ff_spdif_bswap_buf16((uint16_t *)pkt->data, (uint16_t *)pkt->data, pkt->size >> 1);
     183             :     else
     184           0 :         bswap_buf24(pkt->data, pkt->size);
     185             : 
     186           0 :     if (!s->nb_streams) {
     187           0 :         AVStream *st = avformat_new_stream(s, NULL);
     188           0 :         if (!st) {
     189           0 :             av_packet_unref(pkt);
     190           0 :             return AVERROR(ENOMEM);
     191             :         }
     192           0 :         st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     193           0 :         st->codecpar->codec_id   = codec;
     194             :     }
     195             : 
     196           0 :     return 0;
     197             : }
     198             : 
     199             : AVInputFormat ff_s337m_demuxer = {
     200             :     .name           = "s337m",
     201             :     .long_name      = NULL_IF_CONFIG_SMALL("SMPTE 337M"),
     202             :     .read_probe     = s337m_probe,
     203             :     .read_header    = s337m_read_header,
     204             :     .read_packet    = s337m_read_packet,
     205             :     .flags          = AVFMT_GENERIC_INDEX,
     206             : };

Generated by: LCOV version 1.13