LCOV - code coverage report
Current view: top level - libavformat - hnm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4 87 4.6 %
Date: 2017-12-13 10:57:33 Functions: 1 4 25.0 %

          Line data    Source code
       1             : /*
       2             :  * Cryo Interactive Entertainment HNM4 demuxer
       3             :  *
       4             :  * Copyright (c) 2012 David Kment
       5             :  *
       6             :  * This file is part of FFmpeg .
       7             :  *
       8             :  * FFmpeg  is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg  is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg ; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include <inttypes.h>
      24             : 
      25             : #include "libavutil/intreadwrite.h"
      26             : #include "avformat.h"
      27             : #include "internal.h"
      28             : 
      29             : #define HNM4_TAG MKTAG('H', 'N', 'M', '4')
      30             : 
      31             : #define HNM4_SAMPLE_RATE 22050
      32             : #define HNM4_FRAME_FPS 24
      33             : 
      34             : #define HNM4_CHUNK_ID_PL 19536
      35             : #define HNM4_CHUNK_ID_IZ 23113
      36             : #define HNM4_CHUNK_ID_IU 21833
      37             : #define HNM4_CHUNK_ID_SD 17491
      38             : 
      39             : typedef struct Hnm4DemuxContext {
      40             :     uint8_t version;
      41             :     uint16_t width;
      42             :     uint16_t height;
      43             :     uint32_t filesize;
      44             :     uint32_t frames;
      45             :     uint32_t taboffset;
      46             :     uint16_t bits;
      47             :     uint16_t channels;
      48             :     uint32_t framesize;
      49             :     uint32_t currentframe;
      50             :     int64_t pts;
      51             :     uint32_t superchunk_remaining;
      52             :     AVPacket vpkt;
      53             : } Hnm4DemuxContext;
      54             : 
      55        6130 : static int hnm_probe(AVProbeData *p)
      56             : {
      57        6130 :     if (p->buf_size < 4)
      58           0 :         return 0;
      59             : 
      60             :     // check for HNM4 header.
      61             :     // currently only HNM v4/v4A is supported
      62        6130 :     if (AV_RL32(&p->buf[0]) == HNM4_TAG)
      63           0 :         return AVPROBE_SCORE_MAX;
      64             : 
      65        6130 :     return 0;
      66             : }
      67             : 
      68           0 : static int hnm_read_header(AVFormatContext *s)
      69             : {
      70           0 :     Hnm4DemuxContext *hnm = s->priv_data;
      71           0 :     AVIOContext *pb = s->pb;
      72             :     AVStream *vst;
      73             : 
      74             :     /* default context members */
      75           0 :     hnm->pts = 0;
      76           0 :     av_init_packet(&hnm->vpkt);
      77           0 :     hnm->vpkt.data = NULL;
      78           0 :     hnm->vpkt.size = 0;
      79             : 
      80           0 :     hnm->superchunk_remaining = 0;
      81             : 
      82           0 :     avio_skip(pb, 8);
      83           0 :     hnm->width     = avio_rl16(pb);
      84           0 :     hnm->height    = avio_rl16(pb);
      85           0 :     hnm->filesize  = avio_rl32(pb);
      86           0 :     hnm->frames    = avio_rl32(pb);
      87           0 :     hnm->taboffset = avio_rl32(pb);
      88           0 :     hnm->bits      = avio_rl16(pb);
      89           0 :     hnm->channels  = avio_rl16(pb);
      90           0 :     hnm->framesize = avio_rl32(pb);
      91           0 :     avio_skip(pb, 32);
      92             : 
      93           0 :     hnm->currentframe = 0;
      94             : 
      95           0 :     if (hnm->width  < 256 || hnm->width  > 640 ||
      96           0 :         hnm->height < 150 || hnm->height > 480) {
      97           0 :         av_log(s, AV_LOG_ERROR,
      98           0 :                "invalid resolution: %ux%u\n", hnm->width, hnm->height);
      99           0 :         return AVERROR_INVALIDDATA;
     100             :     }
     101             : 
     102             :     // TODO: find a better way to detect HNM4A
     103           0 :     if (hnm->width == 640)
     104           0 :         hnm->version = 0x4a;
     105             :     else
     106           0 :         hnm->version = 0x40;
     107             : 
     108           0 :     if (!(vst = avformat_new_stream(s, NULL)))
     109           0 :         return AVERROR(ENOMEM);
     110             : 
     111           0 :     vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     112           0 :     vst->codecpar->codec_id   = AV_CODEC_ID_HNM4_VIDEO;
     113           0 :     vst->codecpar->codec_tag  = 0;
     114           0 :     vst->codecpar->width      = hnm->width;
     115           0 :     vst->codecpar->height     = hnm->height;
     116           0 :     vst->codecpar->extradata  = av_mallocz(1);
     117             : 
     118           0 :     vst->codecpar->extradata_size = 1;
     119           0 :     memcpy(vst->codecpar->extradata, &hnm->version, 1);
     120             : 
     121           0 :     vst->start_time = 0;
     122             : 
     123           0 :     avpriv_set_pts_info(vst, 33, 1, HNM4_FRAME_FPS);
     124             : 
     125           0 :     return 0;
     126             : }
     127             : 
     128           0 : static int hnm_read_packet(AVFormatContext *s, AVPacket *pkt)
     129             : {
     130           0 :     Hnm4DemuxContext *hnm = s->priv_data;
     131           0 :     AVIOContext *pb = s->pb;
     132           0 :     int ret = 0;
     133             : 
     134             :     uint32_t superchunk_size, chunk_size;
     135             :     uint16_t chunk_id;
     136             : 
     137           0 :     if (hnm->currentframe == hnm->frames || pb->eof_reached)
     138           0 :         return AVERROR_EOF;
     139             : 
     140           0 :     if (hnm->superchunk_remaining == 0) {
     141             :         /* parse next superchunk */
     142           0 :         superchunk_size = avio_rl24(pb);
     143           0 :         avio_skip(pb, 1);
     144             : 
     145           0 :         hnm->superchunk_remaining = superchunk_size - 4;
     146             :     }
     147             : 
     148           0 :     chunk_size = avio_rl24(pb);
     149           0 :     avio_skip(pb, 1);
     150           0 :     chunk_id = avio_rl16(pb);
     151           0 :     avio_skip(pb, 2);
     152             : 
     153           0 :     if (chunk_size > hnm->superchunk_remaining || !chunk_size) {
     154           0 :         av_log(s, AV_LOG_ERROR,
     155             :                "invalid chunk size: %"PRIu32", offset: %"PRId64"\n",
     156             :                chunk_size, avio_tell(pb));
     157           0 :         avio_skip(pb, hnm->superchunk_remaining - 8);
     158           0 :         hnm->superchunk_remaining = 0;
     159             :     }
     160             : 
     161           0 :     switch (chunk_id) {
     162           0 :     case HNM4_CHUNK_ID_PL:
     163             :     case HNM4_CHUNK_ID_IZ:
     164             :     case HNM4_CHUNK_ID_IU:
     165           0 :         avio_seek(pb, -8, SEEK_CUR);
     166           0 :         ret += av_get_packet(pb, pkt, chunk_size);
     167           0 :         hnm->superchunk_remaining -= chunk_size;
     168           0 :         if (chunk_id == HNM4_CHUNK_ID_IZ || chunk_id == HNM4_CHUNK_ID_IU)
     169           0 :             hnm->currentframe++;
     170           0 :         break;
     171             : 
     172           0 :     case HNM4_CHUNK_ID_SD:
     173           0 :         avio_skip(pb, chunk_size - 8);
     174           0 :         hnm->superchunk_remaining -= chunk_size;
     175           0 :         break;
     176             : 
     177           0 :     default:
     178           0 :         av_log(s, AV_LOG_WARNING, "unknown chunk found: %"PRIu16", offset: %"PRId64"\n",
     179             :                chunk_id, avio_tell(pb));
     180           0 :         avio_skip(pb, chunk_size - 8);
     181           0 :         hnm->superchunk_remaining -= chunk_size;
     182           0 :         break;
     183             :     }
     184             : 
     185           0 :     return ret;
     186             : }
     187             : 
     188           0 : static int hnm_read_close(AVFormatContext *s)
     189             : {
     190           0 :     Hnm4DemuxContext *hnm = s->priv_data;
     191             : 
     192           0 :     if (hnm->vpkt.size > 0)
     193           0 :         av_packet_unref(&hnm->vpkt);
     194             : 
     195           0 :     return 0;
     196             : }
     197             : 
     198             : AVInputFormat ff_hnm_demuxer = {
     199             :     .name           = "hnm",
     200             :     .long_name      = NULL_IF_CONFIG_SMALL("Cryo HNM v4"),
     201             :     .priv_data_size = sizeof(Hnm4DemuxContext),
     202             :     .read_probe     = hnm_probe,
     203             :     .read_header    = hnm_read_header,
     204             :     .read_packet    = hnm_read_packet,
     205             :     .read_close     = hnm_read_close,
     206             :     .flags          = AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH
     207             : };

Generated by: LCOV version 1.13