Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * DXA demuxer
  3.  * Copyright (c) 2007 Konstantin Shishkov
  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. #include "libavutil/intreadwrite.h"
  23. #include "avformat.h"
  24. #include "internal.h"
  25. #include "riff.h"
  26.  
  27. #define DXA_EXTRA_SIZE  9
  28.  
  29. typedef struct{
  30.     int frames;
  31.     int has_sound;
  32.     int bpc;
  33.     uint32_t bytes_left;
  34.     int64_t wavpos, vidpos;
  35.     int readvid;
  36. }DXAContext;
  37.  
  38. static int dxa_probe(AVProbeData *p)
  39. {
  40.     int w, h;
  41.     if (p->buf_size < 15)
  42.         return 0;
  43.     w = AV_RB16(p->buf + 11);
  44.     h = AV_RB16(p->buf + 13);
  45.     /* check file header */
  46.     if (p->buf[0] == 'D' && p->buf[1] == 'E' &&
  47.         p->buf[2] == 'X' && p->buf[3] == 'A' &&
  48.         w && w <= 2048 && h && h <= 2048)
  49.         return AVPROBE_SCORE_MAX;
  50.     else
  51.         return 0;
  52. }
  53.  
  54. static int dxa_read_header(AVFormatContext *s)
  55. {
  56.     AVIOContext *pb = s->pb;
  57.     DXAContext *c = s->priv_data;
  58.     AVStream *st, *ast;
  59.     uint32_t tag;
  60.     int32_t fps;
  61.     int w, h;
  62.     int num, den;
  63.     int flags;
  64.     int ret;
  65.  
  66.     tag = avio_rl32(pb);
  67.     if (tag != MKTAG('D', 'E', 'X', 'A'))
  68.         return AVERROR_INVALIDDATA;
  69.     flags = avio_r8(pb);
  70.     c->frames = avio_rb16(pb);
  71.     if(!c->frames){
  72.         av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
  73.         return AVERROR_INVALIDDATA;
  74.     }
  75.  
  76.     fps = avio_rb32(pb);
  77.     if(fps > 0){
  78.         den = 1000;
  79.         num = fps;
  80.     }else if (fps < 0){
  81.         den = 100000;
  82.         num = -fps;
  83.     }else{
  84.         den = 10;
  85.         num = 1;
  86.     }
  87.     w = avio_rb16(pb);
  88.     h = avio_rb16(pb);
  89.     c->has_sound = 0;
  90.  
  91.     st = avformat_new_stream(s, NULL);
  92.     if (!st)
  93.         return AVERROR(ENOMEM);
  94.  
  95.     // Parse WAV data header
  96.     if(avio_rl32(pb) == MKTAG('W', 'A', 'V', 'E')){
  97.         uint32_t size, fsize;
  98.         c->has_sound = 1;
  99.         size = avio_rb32(pb);
  100.         c->vidpos = avio_tell(pb) + size;
  101.         avio_skip(pb, 16);
  102.         fsize = avio_rl32(pb);
  103.  
  104.         ast = avformat_new_stream(s, NULL);
  105.         if (!ast)
  106.             return AVERROR(ENOMEM);
  107.         ret = ff_get_wav_header(pb, ast->codec, fsize);
  108.         if (ret < 0)
  109.             return ret;
  110.         if (ast->codec->sample_rate > 0)
  111.             avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
  112.         // find 'data' chunk
  113.         while(avio_tell(pb) < c->vidpos && !url_feof(pb)){
  114.             tag = avio_rl32(pb);
  115.             fsize = avio_rl32(pb);
  116.             if(tag == MKTAG('d', 'a', 't', 'a')) break;
  117.             avio_skip(pb, fsize);
  118.         }
  119.         c->bpc = (fsize + c->frames - 1) / c->frames;
  120.         if(ast->codec->block_align)
  121.             c->bpc = ((c->bpc + ast->codec->block_align - 1) / ast->codec->block_align) * ast->codec->block_align;
  122.         c->bytes_left = fsize;
  123.         c->wavpos = avio_tell(pb);
  124.         avio_seek(pb, c->vidpos, SEEK_SET);
  125.     }
  126.  
  127.     /* now we are ready: build format streams */
  128.     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  129.     st->codec->codec_id   = AV_CODEC_ID_DXA;
  130.     st->codec->width      = w;
  131.     st->codec->height     = h;
  132.     av_reduce(&den, &num, den, num, (1UL<<31)-1);
  133.     avpriv_set_pts_info(st, 33, num, den);
  134.     /* flags & 0x80 means that image is interlaced,
  135.      * flags & 0x40 means that image has double height
  136.      * either way set true height
  137.      */
  138.     if(flags & 0xC0){
  139.         st->codec->height >>= 1;
  140.     }
  141.     c->readvid = !c->has_sound;
  142.     c->vidpos  = avio_tell(pb);
  143.     s->start_time = 0;
  144.     s->duration = (int64_t)c->frames * AV_TIME_BASE * num / den;
  145.     av_log(s, AV_LOG_DEBUG, "%d frame(s)\n",c->frames);
  146.  
  147.     return 0;
  148. }
  149.  
  150. static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
  151. {
  152.     DXAContext *c = s->priv_data;
  153.     int ret;
  154.     uint32_t size;
  155.     uint8_t buf[DXA_EXTRA_SIZE], pal[768+4];
  156.     int pal_size = 0;
  157.  
  158.     if(!c->readvid && c->has_sound && c->bytes_left){
  159.         c->readvid = 1;
  160.         avio_seek(s->pb, c->wavpos, SEEK_SET);
  161.         size = FFMIN(c->bytes_left, c->bpc);
  162.         ret = av_get_packet(s->pb, pkt, size);
  163.         pkt->stream_index = 1;
  164.         if(ret != size)
  165.             return AVERROR(EIO);
  166.         c->bytes_left -= size;
  167.         c->wavpos = avio_tell(s->pb);
  168.         return 0;
  169.     }
  170.     avio_seek(s->pb, c->vidpos, SEEK_SET);
  171.     while(!url_feof(s->pb) && c->frames){
  172.         avio_read(s->pb, buf, 4);
  173.         switch(AV_RL32(buf)){
  174.         case MKTAG('N', 'U', 'L', 'L'):
  175.             if(av_new_packet(pkt, 4 + pal_size) < 0)
  176.                 return AVERROR(ENOMEM);
  177.             pkt->stream_index = 0;
  178.             if(pal_size) memcpy(pkt->data, pal, pal_size);
  179.             memcpy(pkt->data + pal_size, buf, 4);
  180.             c->frames--;
  181.             c->vidpos = avio_tell(s->pb);
  182.             c->readvid = 0;
  183.             return 0;
  184.         case MKTAG('C', 'M', 'A', 'P'):
  185.             pal_size = 768+4;
  186.             memcpy(pal, buf, 4);
  187.             avio_read(s->pb, pal + 4, 768);
  188.             break;
  189.         case MKTAG('F', 'R', 'A', 'M'):
  190.             avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4);
  191.             size = AV_RB32(buf + 5);
  192.             if(size > 0xFFFFFF){
  193.                 av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size);
  194.                 return AVERROR_INVALIDDATA;
  195.             }
  196.             if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0)
  197.                 return AVERROR(ENOMEM);
  198.             memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE);
  199.             ret = avio_read(s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size);
  200.             if(ret != size){
  201.                 av_free_packet(pkt);
  202.                 return AVERROR(EIO);
  203.             }
  204.             if(pal_size) memcpy(pkt->data, pal, pal_size);
  205.             pkt->stream_index = 0;
  206.             c->frames--;
  207.             c->vidpos = avio_tell(s->pb);
  208.             c->readvid = 0;
  209.             return 0;
  210.         default:
  211.             av_log(s, AV_LOG_ERROR, "Unknown tag %c%c%c%c\n", buf[0], buf[1], buf[2], buf[3]);
  212.             return AVERROR_INVALIDDATA;
  213.         }
  214.     }
  215.     return AVERROR_EOF;
  216. }
  217.  
  218. AVInputFormat ff_dxa_demuxer = {
  219.     .name           = "dxa",
  220.     .long_name      = NULL_IF_CONFIG_SMALL("DXA"),
  221.     .priv_data_size = sizeof(DXAContext),
  222.     .read_probe     = dxa_probe,
  223.     .read_header    = dxa_read_header,
  224.     .read_packet    = dxa_read_packet,
  225. };
  226.