libavformat/idroqdec.c
Go to the documentation of this file.
00001 /*
00002  * id RoQ (.roq) File Demuxer
00003  * Copyright (c) 2003 The ffmpeg Project
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00030 #include "libavutil/intreadwrite.h"
00031 #include "avformat.h"
00032 #include "internal.h"
00033 
00034 #define RoQ_MAGIC_NUMBER 0x1084
00035 #define RoQ_CHUNK_PREAMBLE_SIZE 8
00036 #define RoQ_AUDIO_SAMPLE_RATE 22050
00037 #define RoQ_CHUNKS_TO_SCAN 30
00038 
00039 #define RoQ_INFO           0x1001
00040 #define RoQ_QUAD_CODEBOOK  0x1002
00041 #define RoQ_QUAD_VQ        0x1011
00042 #define RoQ_SOUND_MONO     0x1020
00043 #define RoQ_SOUND_STEREO   0x1021
00044 
00045 typedef struct RoqDemuxContext {
00046 
00047     int frame_rate;
00048     int width;
00049     int height;
00050     int audio_channels;
00051 
00052     int video_stream_index;
00053     int audio_stream_index;
00054 
00055     int64_t video_pts;
00056     unsigned int audio_frame_count;
00057 
00058 } RoqDemuxContext;
00059 
00060 static int roq_probe(AVProbeData *p)
00061 {
00062     if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) ||
00063         (AV_RL32(&p->buf[2]) != 0xFFFFFFFF))
00064         return 0;
00065 
00066     return AVPROBE_SCORE_MAX;
00067 }
00068 
00069 static int roq_read_header(AVFormatContext *s,
00070                            AVFormatParameters *ap)
00071 {
00072     RoqDemuxContext *roq = s->priv_data;
00073     AVIOContext *pb = s->pb;
00074     unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
00075 
00076     /* get the main header */
00077     if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00078         RoQ_CHUNK_PREAMBLE_SIZE)
00079         return AVERROR(EIO);
00080     roq->frame_rate = AV_RL16(&preamble[6]);
00081 
00082     /* init private context parameters */
00083     roq->width = roq->height = roq->audio_channels = roq->video_pts =
00084     roq->audio_frame_count = 0;
00085     roq->audio_stream_index = -1;
00086     roq->video_stream_index = -1;
00087 
00088     s->ctx_flags |= AVFMTCTX_NOHEADER;
00089 
00090     return 0;
00091 }
00092 
00093 static int roq_read_packet(AVFormatContext *s,
00094                            AVPacket *pkt)
00095 {
00096     RoqDemuxContext *roq = s->priv_data;
00097     AVIOContext *pb = s->pb;
00098     int ret = 0;
00099     unsigned int chunk_size;
00100     unsigned int chunk_type;
00101     unsigned int codebook_size;
00102     unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
00103     int packet_read = 0;
00104     int64_t codebook_offset;
00105 
00106     while (!packet_read) {
00107 
00108         if (s->pb->eof_reached)
00109             return AVERROR(EIO);
00110 
00111         /* get the next chunk preamble */
00112         if ((ret = avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) !=
00113             RoQ_CHUNK_PREAMBLE_SIZE)
00114             return AVERROR(EIO);
00115 
00116         chunk_type = AV_RL16(&preamble[0]);
00117         chunk_size = AV_RL32(&preamble[2]);
00118         if(chunk_size > INT_MAX)
00119             return AVERROR_INVALIDDATA;
00120 
00121         switch (chunk_type) {
00122 
00123         case RoQ_INFO:
00124             if (roq->video_stream_index == -1) {
00125                 AVStream *st = avformat_new_stream(s, NULL);
00126                 if (!st)
00127                     return AVERROR(ENOMEM);
00128                 avpriv_set_pts_info(st, 63, 1, roq->frame_rate);
00129                 roq->video_stream_index = st->index;
00130                 st->codec->codec_type   = AVMEDIA_TYPE_VIDEO;
00131                 st->codec->codec_id     = CODEC_ID_ROQ;
00132                 st->codec->codec_tag    = 0;  /* no fourcc */
00133 
00134                 if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE)
00135                     return AVERROR(EIO);
00136                 st->codec->width  = roq->width  = AV_RL16(preamble);
00137                 st->codec->height = roq->height = AV_RL16(preamble + 2);
00138                 break;
00139             }
00140             /* don't care about this chunk anymore */
00141             avio_skip(pb, RoQ_CHUNK_PREAMBLE_SIZE);
00142             break;
00143 
00144         case RoQ_QUAD_CODEBOOK:
00145             if (roq->video_stream_index < 0)
00146                 return AVERROR_INVALIDDATA;
00147             /* packet needs to contain both this codebook and next VQ chunk */
00148             codebook_offset = avio_tell(pb) - RoQ_CHUNK_PREAMBLE_SIZE;
00149             codebook_size = chunk_size;
00150             avio_skip(pb, codebook_size);
00151             if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00152                 RoQ_CHUNK_PREAMBLE_SIZE)
00153                 return AVERROR(EIO);
00154             chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 +
00155                 codebook_size;
00156 
00157             /* rewind */
00158             avio_seek(pb, codebook_offset, SEEK_SET);
00159 
00160             /* load up the packet */
00161             ret= av_get_packet(pb, pkt, chunk_size);
00162             if (ret != chunk_size)
00163                 return AVERROR(EIO);
00164             pkt->stream_index = roq->video_stream_index;
00165             pkt->pts = roq->video_pts++;
00166 
00167             packet_read = 1;
00168             break;
00169 
00170         case RoQ_SOUND_MONO:
00171         case RoQ_SOUND_STEREO:
00172             if (roq->audio_stream_index == -1) {
00173                 AVStream *st = avformat_new_stream(s, NULL);
00174                 if (!st)
00175                     return AVERROR(ENOMEM);
00176                 avpriv_set_pts_info(st, 32, 1, RoQ_AUDIO_SAMPLE_RATE);
00177                 roq->audio_stream_index = st->index;
00178                 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00179                 st->codec->codec_id = CODEC_ID_ROQ_DPCM;
00180                 st->codec->codec_tag = 0;  /* no tag */
00181                 st->codec->channels = roq->audio_channels = chunk_type == RoQ_SOUND_STEREO ? 2 : 1;
00182                 st->codec->sample_rate = RoQ_AUDIO_SAMPLE_RATE;
00183                 st->codec->bits_per_coded_sample = 16;
00184                 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
00185                     st->codec->bits_per_coded_sample;
00186                 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
00187             }
00188         case RoQ_QUAD_VQ:
00189             if (chunk_type == RoQ_QUAD_VQ) {
00190                 if (roq->video_stream_index < 0)
00191                     return AVERROR_INVALIDDATA;
00192             }
00193 
00194             /* load up the packet */
00195             if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE))
00196                 return AVERROR(EIO);
00197             /* copy over preamble */
00198             memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE);
00199 
00200             if (chunk_type == RoQ_QUAD_VQ) {
00201                 pkt->stream_index = roq->video_stream_index;
00202                 pkt->pts = roq->video_pts++;
00203             } else {
00204                 pkt->stream_index = roq->audio_stream_index;
00205                 pkt->pts = roq->audio_frame_count;
00206                 roq->audio_frame_count += (chunk_size / roq->audio_channels);
00207             }
00208 
00209             pkt->pos= avio_tell(pb);
00210             ret = avio_read(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE,
00211                 chunk_size);
00212             if (ret != chunk_size)
00213                 ret = AVERROR(EIO);
00214 
00215             packet_read = 1;
00216             break;
00217 
00218         default:
00219             av_log(s, AV_LOG_ERROR, "  unknown RoQ chunk (%04X)\n", chunk_type);
00220             return AVERROR_INVALIDDATA;
00221         }
00222     }
00223 
00224     return ret;
00225 }
00226 
00227 AVInputFormat ff_roq_demuxer = {
00228     .name           = "RoQ",
00229     .long_name      = NULL_IF_CONFIG_SMALL("id RoQ format"),
00230     .priv_data_size = sizeof(RoqDemuxContext),
00231     .read_probe     = roq_probe,
00232     .read_header    = roq_read_header,
00233     .read_packet    = roq_read_packet,
00234 };