annotate ffmpeg/libavformat/4xm.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * 4X Technologies .4xm File Demuxer (no muxer)
yading@11 3 * Copyright (c) 2003 The ffmpeg Project
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * 4X Technologies file demuxer
yading@11 25 * by Mike Melanson (melanson@pcisys.net)
yading@11 26 * for more information on the .4xm file format, visit:
yading@11 27 * http://www.pcisys.net/~melanson/codecs/
yading@11 28 */
yading@11 29
yading@11 30 #include "libavutil/intreadwrite.h"
yading@11 31 #include "libavutil/intfloat.h"
yading@11 32 #include "avformat.h"
yading@11 33 #include "internal.h"
yading@11 34
yading@11 35 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
yading@11 36 #define FOURXMV_TAG MKTAG('4', 'X', 'M', 'V')
yading@11 37 #define LIST_TAG MKTAG('L', 'I', 'S', 'T')
yading@11 38 #define HEAD_TAG MKTAG('H', 'E', 'A', 'D')
yading@11 39 #define TRK__TAG MKTAG('T', 'R', 'K', '_')
yading@11 40 #define MOVI_TAG MKTAG('M', 'O', 'V', 'I')
yading@11 41 #define VTRK_TAG MKTAG('V', 'T', 'R', 'K')
yading@11 42 #define STRK_TAG MKTAG('S', 'T', 'R', 'K')
yading@11 43 #define std__TAG MKTAG('s', 't', 'd', '_')
yading@11 44 #define name_TAG MKTAG('n', 'a', 'm', 'e')
yading@11 45 #define vtrk_TAG MKTAG('v', 't', 'r', 'k')
yading@11 46 #define strk_TAG MKTAG('s', 't', 'r', 'k')
yading@11 47 #define ifrm_TAG MKTAG('i', 'f', 'r', 'm')
yading@11 48 #define pfrm_TAG MKTAG('p', 'f', 'r', 'm')
yading@11 49 #define cfrm_TAG MKTAG('c', 'f', 'r', 'm')
yading@11 50 #define ifr2_TAG MKTAG('i', 'f', 'r', '2')
yading@11 51 #define pfr2_TAG MKTAG('p', 'f', 'r', '2')
yading@11 52 #define cfr2_TAG MKTAG('c', 'f', 'r', '2')
yading@11 53 #define snd__TAG MKTAG('s', 'n', 'd', '_')
yading@11 54
yading@11 55 #define vtrk_SIZE 0x44
yading@11 56 #define strk_SIZE 0x28
yading@11 57
yading@11 58 #define GET_LIST_HEADER() \
yading@11 59 fourcc_tag = avio_rl32(pb); \
yading@11 60 size = avio_rl32(pb); \
yading@11 61 if (fourcc_tag != LIST_TAG) \
yading@11 62 return AVERROR_INVALIDDATA; \
yading@11 63 fourcc_tag = avio_rl32(pb);
yading@11 64
yading@11 65 typedef struct AudioTrack {
yading@11 66 int sample_rate;
yading@11 67 int bits;
yading@11 68 int channels;
yading@11 69 int stream_index;
yading@11 70 int adpcm;
yading@11 71 int64_t audio_pts;
yading@11 72 } AudioTrack;
yading@11 73
yading@11 74 typedef struct FourxmDemuxContext {
yading@11 75 int width;
yading@11 76 int height;
yading@11 77 int video_stream_index;
yading@11 78 int track_count;
yading@11 79 AudioTrack *tracks;
yading@11 80
yading@11 81 int64_t video_pts;
yading@11 82 float fps;
yading@11 83 } FourxmDemuxContext;
yading@11 84
yading@11 85 static int fourxm_probe(AVProbeData *p)
yading@11 86 {
yading@11 87 if ((AV_RL32(&p->buf[0]) != RIFF_TAG) ||
yading@11 88 (AV_RL32(&p->buf[8]) != FOURXMV_TAG))
yading@11 89 return 0;
yading@11 90
yading@11 91 return AVPROBE_SCORE_MAX;
yading@11 92 }
yading@11 93
yading@11 94 static int fourxm_read_header(AVFormatContext *s)
yading@11 95 {
yading@11 96 AVIOContext *pb = s->pb;
yading@11 97 unsigned int fourcc_tag;
yading@11 98 unsigned int size;
yading@11 99 int header_size;
yading@11 100 FourxmDemuxContext *fourxm = s->priv_data;
yading@11 101 unsigned char *header;
yading@11 102 int i, ret;
yading@11 103 AVStream *st;
yading@11 104
yading@11 105 fourxm->track_count = 0;
yading@11 106 fourxm->tracks = NULL;
yading@11 107 fourxm->fps = 1.0;
yading@11 108
yading@11 109 /* skip the first 3 32-bit numbers */
yading@11 110 avio_skip(pb, 12);
yading@11 111
yading@11 112 /* check for LIST-HEAD */
yading@11 113 GET_LIST_HEADER();
yading@11 114 header_size = size - 4;
yading@11 115 if (fourcc_tag != HEAD_TAG || header_size < 0)
yading@11 116 return AVERROR_INVALIDDATA;
yading@11 117
yading@11 118 /* allocate space for the header and load the whole thing */
yading@11 119 header = av_malloc(header_size);
yading@11 120 if (!header)
yading@11 121 return AVERROR(ENOMEM);
yading@11 122 if (avio_read(pb, header, header_size) != header_size){
yading@11 123 av_free(header);
yading@11 124 return AVERROR(EIO);
yading@11 125 }
yading@11 126
yading@11 127 /* take the lazy approach and search for any and all vtrk and strk chunks */
yading@11 128 for (i = 0; i < header_size - 8; i++) {
yading@11 129 fourcc_tag = AV_RL32(&header[i]);
yading@11 130 size = AV_RL32(&header[i + 4]);
yading@11 131 if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
yading@11 132 av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
yading@11 133 return AVERROR_INVALIDDATA;
yading@11 134 }
yading@11 135
yading@11 136 if (fourcc_tag == std__TAG) {
yading@11 137 if (header_size < i + 16) {
yading@11 138 av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
yading@11 139 return AVERROR_INVALIDDATA;
yading@11 140 }
yading@11 141 fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
yading@11 142 } else if (fourcc_tag == vtrk_TAG) {
yading@11 143 /* check that there is enough data */
yading@11 144 if (size != vtrk_SIZE) {
yading@11 145 ret= AVERROR_INVALIDDATA;
yading@11 146 goto fail;
yading@11 147 }
yading@11 148 fourxm->width = AV_RL32(&header[i + 36]);
yading@11 149 fourxm->height = AV_RL32(&header[i + 40]);
yading@11 150
yading@11 151 /* allocate a new AVStream */
yading@11 152 st = avformat_new_stream(s, NULL);
yading@11 153 if (!st){
yading@11 154 ret= AVERROR(ENOMEM);
yading@11 155 goto fail;
yading@11 156 }
yading@11 157 avpriv_set_pts_info(st, 60, 1, fourxm->fps);
yading@11 158
yading@11 159 fourxm->video_stream_index = st->index;
yading@11 160
yading@11 161 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 162 st->codec->codec_id = AV_CODEC_ID_4XM;
yading@11 163 st->codec->extradata_size = 4;
yading@11 164 st->codec->extradata = av_malloc(4);
yading@11 165 AV_WL32(st->codec->extradata, AV_RL32(&header[i + 16]));
yading@11 166 st->codec->width = fourxm->width;
yading@11 167 st->codec->height = fourxm->height;
yading@11 168
yading@11 169 i += 8 + size;
yading@11 170 } else if (fourcc_tag == strk_TAG) {
yading@11 171 int current_track;
yading@11 172 /* check that there is enough data */
yading@11 173 if (size != strk_SIZE) {
yading@11 174 ret= AVERROR_INVALIDDATA;
yading@11 175 goto fail;
yading@11 176 }
yading@11 177 current_track = AV_RL32(&header[i + 8]);
yading@11 178 if((unsigned)current_track >= UINT_MAX / sizeof(AudioTrack) - 1){
yading@11 179 av_log(s, AV_LOG_ERROR, "current_track too large\n");
yading@11 180 ret = AVERROR_INVALIDDATA;
yading@11 181 goto fail;
yading@11 182 }
yading@11 183 if (current_track + 1 > fourxm->track_count) {
yading@11 184 fourxm->tracks = av_realloc_f(fourxm->tracks,
yading@11 185 sizeof(AudioTrack),
yading@11 186 current_track + 1);
yading@11 187 if (!fourxm->tracks) {
yading@11 188 ret = AVERROR(ENOMEM);
yading@11 189 goto fail;
yading@11 190 }
yading@11 191 memset(&fourxm->tracks[fourxm->track_count], 0,
yading@11 192 sizeof(AudioTrack) * (current_track + 1 - fourxm->track_count));
yading@11 193 fourxm->track_count = current_track + 1;
yading@11 194 }
yading@11 195 fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]);
yading@11 196 fourxm->tracks[current_track].channels = AV_RL32(&header[i + 36]);
yading@11 197 fourxm->tracks[current_track].sample_rate = AV_RL32(&header[i + 40]);
yading@11 198 fourxm->tracks[current_track].bits = AV_RL32(&header[i + 44]);
yading@11 199 fourxm->tracks[current_track].audio_pts = 0;
yading@11 200 if( fourxm->tracks[current_track].channels <= 0
yading@11 201 || fourxm->tracks[current_track].sample_rate <= 0
yading@11 202 || fourxm->tracks[current_track].bits < 0){
yading@11 203 av_log(s, AV_LOG_ERROR, "audio header invalid\n");
yading@11 204 ret = AVERROR_INVALIDDATA;
yading@11 205 goto fail;
yading@11 206 }
yading@11 207 if(!fourxm->tracks[current_track].adpcm && fourxm->tracks[current_track].bits<8){
yading@11 208 av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
yading@11 209 ret = AVERROR_INVALIDDATA;
yading@11 210 goto fail;
yading@11 211 }
yading@11 212 i += 8 + size;
yading@11 213
yading@11 214 /* allocate a new AVStream */
yading@11 215 st = avformat_new_stream(s, NULL);
yading@11 216 if (!st){
yading@11 217 ret= AVERROR(ENOMEM);
yading@11 218 goto fail;
yading@11 219 }
yading@11 220
yading@11 221 st->id = current_track;
yading@11 222 avpriv_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate);
yading@11 223
yading@11 224 fourxm->tracks[current_track].stream_index = st->index;
yading@11 225
yading@11 226 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 227 st->codec->codec_tag = 0;
yading@11 228 st->codec->channels = fourxm->tracks[current_track].channels;
yading@11 229 st->codec->sample_rate = fourxm->tracks[current_track].sample_rate;
yading@11 230 st->codec->bits_per_coded_sample = fourxm->tracks[current_track].bits;
yading@11 231 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
yading@11 232 st->codec->bits_per_coded_sample;
yading@11 233 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
yading@11 234 if (fourxm->tracks[current_track].adpcm){
yading@11 235 st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
yading@11 236 }else if (st->codec->bits_per_coded_sample == 8){
yading@11 237 st->codec->codec_id = AV_CODEC_ID_PCM_U8;
yading@11 238 }else
yading@11 239 st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
yading@11 240 }
yading@11 241 }
yading@11 242
yading@11 243 /* skip over the LIST-MOVI chunk (which is where the stream should be */
yading@11 244 GET_LIST_HEADER();
yading@11 245 if (fourcc_tag != MOVI_TAG){
yading@11 246 ret= AVERROR_INVALIDDATA;
yading@11 247 goto fail;
yading@11 248 }
yading@11 249
yading@11 250 av_free(header);
yading@11 251 /* initialize context members */
yading@11 252 fourxm->video_pts = -1; /* first frame will push to 0 */
yading@11 253
yading@11 254 return 0;
yading@11 255 fail:
yading@11 256 av_freep(&fourxm->tracks);
yading@11 257 av_free(header);
yading@11 258 return ret;
yading@11 259 }
yading@11 260
yading@11 261 static int fourxm_read_packet(AVFormatContext *s,
yading@11 262 AVPacket *pkt)
yading@11 263 {
yading@11 264 FourxmDemuxContext *fourxm = s->priv_data;
yading@11 265 AVIOContext *pb = s->pb;
yading@11 266 unsigned int fourcc_tag;
yading@11 267 unsigned int size;
yading@11 268 int ret = 0;
yading@11 269 unsigned int track_number;
yading@11 270 int packet_read = 0;
yading@11 271 unsigned char header[8];
yading@11 272 int audio_frame_count;
yading@11 273
yading@11 274 while (!packet_read) {
yading@11 275
yading@11 276 if ((ret = avio_read(s->pb, header, 8)) < 0)
yading@11 277 return ret;
yading@11 278 fourcc_tag = AV_RL32(&header[0]);
yading@11 279 size = AV_RL32(&header[4]);
yading@11 280 if (url_feof(pb))
yading@11 281 return AVERROR(EIO);
yading@11 282 switch (fourcc_tag) {
yading@11 283
yading@11 284 case LIST_TAG:
yading@11 285 /* this is a good time to bump the video pts */
yading@11 286 fourxm->video_pts ++;
yading@11 287
yading@11 288 /* skip the LIST-* tag and move on to the next fourcc */
yading@11 289 avio_rl32(pb);
yading@11 290 break;
yading@11 291
yading@11 292 case ifrm_TAG:
yading@11 293 case pfrm_TAG:
yading@11 294 case cfrm_TAG:
yading@11 295 case ifr2_TAG:
yading@11 296 case pfr2_TAG:
yading@11 297 case cfr2_TAG:
yading@11 298 /* allocate 8 more bytes than 'size' to account for fourcc
yading@11 299 * and size */
yading@11 300 if (size + 8 < size || av_new_packet(pkt, size + 8))
yading@11 301 return AVERROR(EIO);
yading@11 302 pkt->stream_index = fourxm->video_stream_index;
yading@11 303 pkt->pts = fourxm->video_pts;
yading@11 304 pkt->pos = avio_tell(s->pb);
yading@11 305 memcpy(pkt->data, header, 8);
yading@11 306 ret = avio_read(s->pb, &pkt->data[8], size);
yading@11 307
yading@11 308 if (ret < 0){
yading@11 309 av_free_packet(pkt);
yading@11 310 }else
yading@11 311 packet_read = 1;
yading@11 312 break;
yading@11 313
yading@11 314 case snd__TAG:
yading@11 315 track_number = avio_rl32(pb);
yading@11 316 avio_skip(pb, 4);
yading@11 317 size-=8;
yading@11 318
yading@11 319 if (track_number < fourxm->track_count && fourxm->tracks[track_number].channels>0) {
yading@11 320 ret= av_get_packet(s->pb, pkt, size);
yading@11 321 if(ret<0)
yading@11 322 return AVERROR(EIO);
yading@11 323 pkt->stream_index =
yading@11 324 fourxm->tracks[track_number].stream_index;
yading@11 325 pkt->pts = fourxm->tracks[track_number].audio_pts;
yading@11 326 packet_read = 1;
yading@11 327
yading@11 328 /* pts accounting */
yading@11 329 audio_frame_count = size;
yading@11 330 if (fourxm->tracks[track_number].adpcm)
yading@11 331 audio_frame_count -=
yading@11 332 2 * (fourxm->tracks[track_number].channels);
yading@11 333 audio_frame_count /=
yading@11 334 fourxm->tracks[track_number].channels;
yading@11 335 if (fourxm->tracks[track_number].adpcm){
yading@11 336 audio_frame_count *= 2;
yading@11 337 }else
yading@11 338 audio_frame_count /=
yading@11 339 (fourxm->tracks[track_number].bits / 8);
yading@11 340 fourxm->tracks[track_number].audio_pts += audio_frame_count;
yading@11 341
yading@11 342 } else {
yading@11 343 avio_skip(pb, size);
yading@11 344 }
yading@11 345 break;
yading@11 346
yading@11 347 default:
yading@11 348 avio_skip(pb, size);
yading@11 349 break;
yading@11 350 }
yading@11 351 }
yading@11 352 return ret;
yading@11 353 }
yading@11 354
yading@11 355 static int fourxm_read_close(AVFormatContext *s)
yading@11 356 {
yading@11 357 FourxmDemuxContext *fourxm = s->priv_data;
yading@11 358
yading@11 359 av_freep(&fourxm->tracks);
yading@11 360
yading@11 361 return 0;
yading@11 362 }
yading@11 363
yading@11 364 AVInputFormat ff_fourxm_demuxer = {
yading@11 365 .name = "4xm",
yading@11 366 .long_name = NULL_IF_CONFIG_SMALL("4X Technologies"),
yading@11 367 .priv_data_size = sizeof(FourxmDemuxContext),
yading@11 368 .read_probe = fourxm_probe,
yading@11 369 .read_header = fourxm_read_header,
yading@11 370 .read_packet = fourxm_read_packet,
yading@11 371 .read_close = fourxm_read_close,
yading@11 372 };