Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. static int hnm_probe(AVProbeData *p)
  56. {
  57.     if (p->buf_size < 4)
  58.         return 0;
  59.  
  60.     // check for HNM4 header.
  61.     // currently only HNM v4/v4A is supported
  62.     if (AV_RL32(&p->buf[0]) == HNM4_TAG)
  63.         return AVPROBE_SCORE_MAX;
  64.  
  65.     return 0;
  66. }
  67.  
  68. static int hnm_read_header(AVFormatContext *s)
  69. {
  70.     Hnm4DemuxContext *hnm = s->priv_data;
  71.     AVIOContext *pb = s->pb;
  72.     AVStream *vst;
  73.  
  74.     /* default context members */
  75.     hnm->pts = 0;
  76.     av_init_packet(&hnm->vpkt);
  77.     hnm->vpkt.data = NULL;
  78.     hnm->vpkt.size = 0;
  79.  
  80.     hnm->superchunk_remaining = 0;
  81.  
  82.     avio_skip(pb, 8);
  83.     hnm->width     = avio_rl16(pb);
  84.     hnm->height    = avio_rl16(pb);
  85.     hnm->filesize  = avio_rl32(pb);
  86.     hnm->frames    = avio_rl32(pb);
  87.     hnm->taboffset = avio_rl32(pb);
  88.     hnm->bits      = avio_rl16(pb);
  89.     hnm->channels  = avio_rl16(pb);
  90.     hnm->framesize = avio_rl32(pb);
  91.     avio_skip(pb, 32);
  92.  
  93.     hnm->currentframe = 0;
  94.  
  95.     if (hnm->width  < 256 || hnm->width  > 640 ||
  96.         hnm->height < 150 || hnm->height > 480) {
  97.         av_log(s, AV_LOG_ERROR,
  98.                "invalid resolution: %ux%u\n", hnm->width, hnm->height);
  99.         return AVERROR_INVALIDDATA;
  100.     }
  101.  
  102.     // TODO: find a better way to detect HNM4A
  103.     if (hnm->width == 640)
  104.         hnm->version = 0x4a;
  105.     else
  106.         hnm->version = 0x40;
  107.  
  108.     if (!(vst = avformat_new_stream(s, NULL)))
  109.         return AVERROR(ENOMEM);
  110.  
  111.     vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  112.     vst->codec->codec_id   = AV_CODEC_ID_HNM4_VIDEO;
  113.     vst->codec->codec_tag  = 0;
  114.     vst->codec->width      = hnm->width;
  115.     vst->codec->height     = hnm->height;
  116.     vst->codec->extradata  = av_mallocz(1);
  117.  
  118.     vst->codec->extradata_size = 1;
  119.     memcpy(vst->codec->extradata, &hnm->version, 1);
  120.  
  121.     vst->start_time = 0;
  122.  
  123.     avpriv_set_pts_info(vst, 33, 1, HNM4_FRAME_FPS);
  124.  
  125.     return 0;
  126. }
  127.  
  128. static int hnm_read_packet(AVFormatContext *s, AVPacket *pkt)
  129. {
  130.     Hnm4DemuxContext *hnm = s->priv_data;
  131.     AVIOContext *pb = s->pb;
  132.     int ret = 0;
  133.  
  134.     uint32_t superchunk_size, chunk_size;
  135.     uint16_t chunk_id;
  136.  
  137.     if (hnm->currentframe == hnm->frames || pb->eof_reached)
  138.         return AVERROR_EOF;
  139.  
  140.     if (hnm->superchunk_remaining == 0) {
  141.         /* parse next superchunk */
  142.         superchunk_size = avio_rl24(pb);
  143.         avio_skip(pb, 1);
  144.  
  145.         hnm->superchunk_remaining = superchunk_size - 4;
  146.     }
  147.  
  148.     chunk_size = avio_rl24(pb);
  149.     avio_skip(pb, 1);
  150.     chunk_id = avio_rl16(pb);
  151.     avio_skip(pb, 2);
  152.  
  153.     if (chunk_size > hnm->superchunk_remaining || !chunk_size) {
  154.         av_log(s, AV_LOG_ERROR,
  155.                "invalid chunk size: %"PRIu32", offset: %"PRId64"\n",
  156.                chunk_size, avio_tell(pb));
  157.         avio_skip(pb, hnm->superchunk_remaining - 8);
  158.         hnm->superchunk_remaining = 0;
  159.     }
  160.  
  161.     switch (chunk_id) {
  162.     case HNM4_CHUNK_ID_PL:
  163.     case HNM4_CHUNK_ID_IZ:
  164.     case HNM4_CHUNK_ID_IU:
  165.         avio_seek(pb, -8, SEEK_CUR);
  166.         ret += av_get_packet(pb, pkt, chunk_size);
  167.         hnm->superchunk_remaining -= chunk_size;
  168.         if (chunk_id == HNM4_CHUNK_ID_IZ || chunk_id == HNM4_CHUNK_ID_IU)
  169.             hnm->currentframe++;
  170.         break;
  171.  
  172.     case HNM4_CHUNK_ID_SD:
  173.         avio_skip(pb, chunk_size - 8);
  174.         hnm->superchunk_remaining -= chunk_size;
  175.         break;
  176.  
  177.     default:
  178.         av_log(s, AV_LOG_WARNING, "unknown chunk found: %"PRIu16", offset: %"PRId64"\n",
  179.                chunk_id, avio_tell(pb));
  180.         avio_skip(pb, chunk_size - 8);
  181.         hnm->superchunk_remaining -= chunk_size;
  182.         break;
  183.     }
  184.  
  185.     return ret;
  186. }
  187.  
  188. static int hnm_read_close(AVFormatContext *s)
  189. {
  190.     Hnm4DemuxContext *hnm = s->priv_data;
  191.  
  192.     if (hnm->vpkt.size > 0)
  193.         av_free_packet(&hnm->vpkt);
  194.  
  195.     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. };
  208.