Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Delphine Software International CIN File Demuxer
  3.  * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * Delphine Software International CIN file demuxer
  25.  */
  26.  
  27. #include "libavutil/channel_layout.h"
  28. #include "libavutil/intreadwrite.h"
  29. #include "avformat.h"
  30. #include "internal.h"
  31. #include "avio_internal.h"
  32.  
  33.  
  34. typedef struct CinFileHeader {
  35.     int video_frame_size;
  36.     int video_frame_width;
  37.     int video_frame_height;
  38.     int audio_frequency;
  39.     int audio_bits;
  40.     int audio_stereo;
  41.     int audio_frame_size;
  42. } CinFileHeader;
  43.  
  44. typedef struct CinFrameHeader {
  45.     int audio_frame_type;
  46.     int video_frame_type;
  47.     int pal_colors_count;
  48.     int audio_frame_size;
  49.     int video_frame_size;
  50. } CinFrameHeader;
  51.  
  52. typedef struct CinDemuxContext {
  53.     int audio_stream_index;
  54.     int video_stream_index;
  55.     CinFileHeader file_header;
  56.     int64_t audio_stream_pts;
  57.     int64_t video_stream_pts;
  58.     CinFrameHeader frame_header;
  59.     int audio_buffer_size;
  60. } CinDemuxContext;
  61.  
  62.  
  63. static int cin_probe(AVProbeData *p)
  64. {
  65.     /* header starts with this special marker */
  66.     if (AV_RL32(&p->buf[0]) != 0x55AA0000)
  67.         return 0;
  68.  
  69.     /* for accuracy, check some header field values */
  70.     if (AV_RL32(&p->buf[12]) != 22050 || p->buf[16] != 16 || p->buf[17] != 0)
  71.         return 0;
  72.  
  73.     return AVPROBE_SCORE_MAX;
  74. }
  75.  
  76. static int cin_read_file_header(CinDemuxContext *cin, AVIOContext *pb) {
  77.     CinFileHeader *hdr = &cin->file_header;
  78.  
  79.     if (avio_rl32(pb) != 0x55AA0000)
  80.         return AVERROR_INVALIDDATA;
  81.  
  82.     hdr->video_frame_size   = avio_rl32(pb);
  83.     hdr->video_frame_width  = avio_rl16(pb);
  84.     hdr->video_frame_height = avio_rl16(pb);
  85.     hdr->audio_frequency    = avio_rl32(pb);
  86.     hdr->audio_bits         = avio_r8(pb);
  87.     hdr->audio_stereo       = avio_r8(pb);
  88.     hdr->audio_frame_size   = avio_rl16(pb);
  89.  
  90.     if (hdr->audio_frequency != 22050 || hdr->audio_bits != 16 || hdr->audio_stereo != 0)
  91.         return AVERROR_INVALIDDATA;
  92.  
  93.     return 0;
  94. }
  95.  
  96. static int cin_read_header(AVFormatContext *s)
  97. {
  98.     int rc;
  99.     CinDemuxContext *cin = s->priv_data;
  100.     CinFileHeader *hdr = &cin->file_header;
  101.     AVIOContext *pb = s->pb;
  102.     AVStream *st;
  103.  
  104.     rc = cin_read_file_header(cin, pb);
  105.     if (rc)
  106.         return rc;
  107.  
  108.     cin->video_stream_pts = 0;
  109.     cin->audio_stream_pts = 0;
  110.     cin->audio_buffer_size = 0;
  111.  
  112.     /* initialize the video decoder stream */
  113.     st = avformat_new_stream(s, NULL);
  114.     if (!st)
  115.         return AVERROR(ENOMEM);
  116.  
  117.     avpriv_set_pts_info(st, 32, 1, 12);
  118.     cin->video_stream_index = st->index;
  119.     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  120.     st->codec->codec_id = AV_CODEC_ID_DSICINVIDEO;
  121.     st->codec->codec_tag = 0;  /* no fourcc */
  122.     st->codec->width = hdr->video_frame_width;
  123.     st->codec->height = hdr->video_frame_height;
  124.  
  125.     /* initialize the audio decoder stream */
  126.     st = avformat_new_stream(s, NULL);
  127.     if (!st)
  128.         return AVERROR(ENOMEM);
  129.  
  130.     avpriv_set_pts_info(st, 32, 1, 22050);
  131.     cin->audio_stream_index = st->index;
  132.     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  133.     st->codec->codec_id = AV_CODEC_ID_DSICINAUDIO;
  134.     st->codec->codec_tag = 0;  /* no tag */
  135.     st->codec->channels = 1;
  136.     st->codec->channel_layout = AV_CH_LAYOUT_MONO;
  137.     st->codec->sample_rate = 22050;
  138.     st->codec->bits_per_coded_sample = 8;
  139.     st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample * st->codec->channels;
  140.  
  141.     return 0;
  142. }
  143.  
  144. static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) {
  145.     CinFrameHeader *hdr = &cin->frame_header;
  146.  
  147.     hdr->video_frame_type = avio_r8(pb);
  148.     hdr->audio_frame_type = avio_r8(pb);
  149.     hdr->pal_colors_count = avio_rl16(pb);
  150.     hdr->video_frame_size = avio_rl32(pb);
  151.     hdr->audio_frame_size = avio_rl32(pb);
  152.  
  153.     if (url_feof(pb) || pb->error)
  154.         return AVERROR(EIO);
  155.  
  156.     if (avio_rl32(pb) != 0xAA55AA55)
  157.         return AVERROR_INVALIDDATA;
  158.     if (hdr->video_frame_size < 0 || hdr->audio_frame_size < 0)
  159.         return AVERROR_INVALIDDATA;
  160.  
  161.     return 0;
  162. }
  163.  
  164. static int cin_read_packet(AVFormatContext *s, AVPacket *pkt)
  165. {
  166.     CinDemuxContext *cin = s->priv_data;
  167.     AVIOContext *pb = s->pb;
  168.     CinFrameHeader *hdr = &cin->frame_header;
  169.     int rc, palette_type, pkt_size;
  170.     int ret;
  171.  
  172.     if (cin->audio_buffer_size == 0) {
  173.         rc = cin_read_frame_header(cin, pb);
  174.         if (rc)
  175.             return rc;
  176.  
  177.         if ((int16_t)hdr->pal_colors_count < 0) {
  178.             hdr->pal_colors_count = -(int16_t)hdr->pal_colors_count;
  179.             palette_type = 1;
  180.         } else {
  181.             palette_type = 0;
  182.         }
  183.  
  184.         /* palette and video packet */
  185.         pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size;
  186.  
  187.         pkt_size = ffio_limit(pb, pkt_size);
  188.  
  189.         ret = av_new_packet(pkt, 4 + pkt_size);
  190.         if (ret < 0)
  191.             return ret;
  192.  
  193.         pkt->stream_index = cin->video_stream_index;
  194.         pkt->pts = cin->video_stream_pts++;
  195.  
  196.         pkt->data[0] = palette_type;
  197.         pkt->data[1] = hdr->pal_colors_count & 0xFF;
  198.         pkt->data[2] = hdr->pal_colors_count >> 8;
  199.         pkt->data[3] = hdr->video_frame_type;
  200.  
  201.         ret = avio_read(pb, &pkt->data[4], pkt_size);
  202.         if (ret < 0) {
  203.             av_free_packet(pkt);
  204.             return ret;
  205.         }
  206.         if (ret < pkt_size)
  207.             av_shrink_packet(pkt, 4 + ret);
  208.  
  209.         /* sound buffer will be processed on next read_packet() call */
  210.         cin->audio_buffer_size = hdr->audio_frame_size;
  211.         return 0;
  212.     }
  213.  
  214.     /* audio packet */
  215.     ret = av_get_packet(pb, pkt, cin->audio_buffer_size);
  216.     if (ret < 0)
  217.         return ret;
  218.  
  219.     pkt->stream_index = cin->audio_stream_index;
  220.     pkt->pts = cin->audio_stream_pts;
  221.     pkt->duration = cin->audio_buffer_size - (pkt->pts == 0);
  222.     cin->audio_stream_pts += pkt->duration;
  223.     cin->audio_buffer_size = 0;
  224.     return 0;
  225. }
  226.  
  227. AVInputFormat ff_dsicin_demuxer = {
  228.     .name           = "dsicin",
  229.     .long_name      = NULL_IF_CONFIG_SMALL("Delphine Software International CIN"),
  230.     .priv_data_size = sizeof(CinDemuxContext),
  231.     .read_probe     = cin_probe,
  232.     .read_header    = cin_read_header,
  233.     .read_packet    = cin_read_packet,
  234. };
  235.