• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/idroq.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 FFmpeg.
00006  *
00007  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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 
00033 #define RoQ_MAGIC_NUMBER 0x1084
00034 #define RoQ_CHUNK_PREAMBLE_SIZE 8
00035 #define RoQ_AUDIO_SAMPLE_RATE 22050
00036 #define RoQ_CHUNKS_TO_SCAN 30
00037 
00038 #define RoQ_INFO           0x1001
00039 #define RoQ_QUAD_CODEBOOK  0x1002
00040 #define RoQ_QUAD_VQ        0x1011
00041 #define RoQ_SOUND_MONO     0x1020
00042 #define RoQ_SOUND_STEREO   0x1021
00043 
00044 typedef struct RoqDemuxContext {
00045 
00046     int width;
00047     int height;
00048     int audio_channels;
00049     int framerate;
00050     int frame_pts_inc;
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     ByteIOContext *pb = s->pb;
00074     AVStream *st;
00075     unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
00076     int i;
00077     unsigned int chunk_size;
00078     unsigned int chunk_type;
00079 
00080     /* get the main header */
00081     if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00082         RoQ_CHUNK_PREAMBLE_SIZE)
00083         return AVERROR(EIO);
00084     roq->framerate = AV_RL16(&preamble[6]);
00085     roq->frame_pts_inc = 90000 / roq->framerate;
00086 
00087     /* init private context parameters */
00088     roq->width = roq->height = roq->audio_channels = roq->video_pts =
00089     roq->audio_frame_count = 0;
00090 
00091     /* scan the first n chunks searching for A/V parameters */
00092     for (i = 0; i < RoQ_CHUNKS_TO_SCAN; i++) {
00093         if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00094             RoQ_CHUNK_PREAMBLE_SIZE)
00095             return AVERROR(EIO);
00096 
00097         chunk_type = AV_RL16(&preamble[0]);
00098         chunk_size = AV_RL32(&preamble[2]);
00099 
00100         switch (chunk_type) {
00101 
00102         case RoQ_INFO:
00103             /* fetch the width and height; reuse the preamble bytes */
00104             if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00105                 RoQ_CHUNK_PREAMBLE_SIZE)
00106                 return AVERROR(EIO);
00107             roq->width = AV_RL16(&preamble[0]);
00108             roq->height = AV_RL16(&preamble[2]);
00109             break;
00110 
00111         case RoQ_QUAD_CODEBOOK:
00112         case RoQ_QUAD_VQ:
00113             /* ignore during this scan */
00114             url_fseek(pb, chunk_size, SEEK_CUR);
00115             break;
00116 
00117         case RoQ_SOUND_MONO:
00118             roq->audio_channels = 1;
00119             url_fseek(pb, chunk_size, SEEK_CUR);
00120             break;
00121 
00122         case RoQ_SOUND_STEREO:
00123             roq->audio_channels = 2;
00124             url_fseek(pb, chunk_size, SEEK_CUR);
00125             break;
00126 
00127         default:
00128             av_log(s, AV_LOG_ERROR, " unknown RoQ chunk type (%04X)\n", AV_RL16(&preamble[0]));
00129             return AVERROR_INVALIDDATA;
00130             break;
00131         }
00132 
00133         /* if all necessary parameters have been gathered, exit early */
00134         if ((roq->width && roq->height) && roq->audio_channels)
00135             break;
00136     }
00137 
00138     /* seek back to the first chunk */
00139     url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_SET);
00140 
00141     /* initialize the decoders */
00142     st = av_new_stream(s, 0);
00143     if (!st)
00144         return AVERROR(ENOMEM);
00145     /* set the pts reference (1 pts = 1/90000) */
00146     av_set_pts_info(st, 33, 1, 90000);
00147     roq->video_stream_index = st->index;
00148     st->codec->codec_type = CODEC_TYPE_VIDEO;
00149     st->codec->codec_id = CODEC_ID_ROQ;
00150     st->codec->codec_tag = 0;  /* no fourcc */
00151     st->codec->width = roq->width;
00152     st->codec->height = roq->height;
00153 
00154     if (roq->audio_channels) {
00155         st = av_new_stream(s, 0);
00156         if (!st)
00157             return AVERROR(ENOMEM);
00158         av_set_pts_info(st, 33, 1, 90000);
00159         roq->audio_stream_index = st->index;
00160         st->codec->codec_type = CODEC_TYPE_AUDIO;
00161         st->codec->codec_id = CODEC_ID_ROQ_DPCM;
00162         st->codec->codec_tag = 0;  /* no tag */
00163         st->codec->channels = roq->audio_channels;
00164         st->codec->sample_rate = RoQ_AUDIO_SAMPLE_RATE;
00165         st->codec->bits_per_coded_sample = 16;
00166         st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
00167             st->codec->bits_per_coded_sample;
00168         st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
00169     }
00170 
00171     return 0;
00172 }
00173 
00174 static int roq_read_packet(AVFormatContext *s,
00175                            AVPacket *pkt)
00176 {
00177     RoqDemuxContext *roq = s->priv_data;
00178     ByteIOContext *pb = s->pb;
00179     int ret = 0;
00180     unsigned int chunk_size;
00181     unsigned int chunk_type;
00182     unsigned int codebook_size;
00183     unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
00184     int packet_read = 0;
00185     int64_t codebook_offset;
00186 
00187     while (!packet_read) {
00188 
00189         if (url_feof(s->pb))
00190             return AVERROR(EIO);
00191 
00192         /* get the next chunk preamble */
00193         if ((ret = get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) !=
00194             RoQ_CHUNK_PREAMBLE_SIZE)
00195             return AVERROR(EIO);
00196 
00197         chunk_type = AV_RL16(&preamble[0]);
00198         chunk_size = AV_RL32(&preamble[2]);
00199         if(chunk_size > INT_MAX)
00200             return AVERROR_INVALIDDATA;
00201 
00202         switch (chunk_type) {
00203 
00204         case RoQ_INFO:
00205             /* don't care about this chunk anymore */
00206             url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_CUR);
00207             break;
00208 
00209         case RoQ_QUAD_CODEBOOK:
00210             /* packet needs to contain both this codebook and next VQ chunk */
00211             codebook_offset = url_ftell(pb) - RoQ_CHUNK_PREAMBLE_SIZE;
00212             codebook_size = chunk_size;
00213             url_fseek(pb, codebook_size, SEEK_CUR);
00214             if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
00215                 RoQ_CHUNK_PREAMBLE_SIZE)
00216                 return AVERROR(EIO);
00217             chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 +
00218                 codebook_size;
00219 
00220             /* rewind */
00221             url_fseek(pb, codebook_offset, SEEK_SET);
00222 
00223             /* load up the packet */
00224             ret= av_get_packet(pb, pkt, chunk_size);
00225             if (ret != chunk_size)
00226                 return AVERROR(EIO);
00227             pkt->stream_index = roq->video_stream_index;
00228             pkt->pts = roq->video_pts;
00229 
00230             roq->video_pts += roq->frame_pts_inc;
00231             packet_read = 1;
00232             break;
00233 
00234         case RoQ_SOUND_MONO:
00235         case RoQ_SOUND_STEREO:
00236         case RoQ_QUAD_VQ:
00237             /* load up the packet */
00238             if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE))
00239                 return AVERROR(EIO);
00240             /* copy over preamble */
00241             memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE);
00242 
00243             if (chunk_type == RoQ_QUAD_VQ) {
00244                 pkt->stream_index = roq->video_stream_index;
00245                 pkt->pts = roq->video_pts;
00246                 roq->video_pts += roq->frame_pts_inc;
00247             } else {
00248                 pkt->stream_index = roq->audio_stream_index;
00249                 pkt->pts = roq->audio_frame_count;
00250                 pkt->pts *= 90000;
00251                 pkt->pts /= RoQ_AUDIO_SAMPLE_RATE;
00252                 roq->audio_frame_count += (chunk_size / roq->audio_channels);
00253             }
00254 
00255             pkt->pos= url_ftell(pb);
00256             ret = get_buffer(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE,
00257                 chunk_size);
00258             if (ret != chunk_size)
00259                 ret = AVERROR(EIO);
00260 
00261             packet_read = 1;
00262             break;
00263 
00264         default:
00265             av_log(s, AV_LOG_ERROR, "  unknown RoQ chunk (%04X)\n", chunk_type);
00266             return AVERROR_INVALIDDATA;
00267             break;
00268         }
00269     }
00270 
00271     return ret;
00272 }
00273 
00274 AVInputFormat roq_demuxer = {
00275     "RoQ",
00276     NULL_IF_CONFIG_SMALL("id RoQ format"),
00277     sizeof(RoqDemuxContext),
00278     roq_probe,
00279     roq_read_header,
00280     roq_read_packet,
00281 };

Generated on Tue Nov 4 2014 12:59:23 for ffmpeg by  doxygen 1.7.1