1/* 2 * THP Demuxer 3 * Copyright (c) 2007 Marco Gerards 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 25typedef struct ThpDemuxContext { 26 int version; 27 int first_frame; 28 int first_framesz; 29 int last_frame; 30 int compoff; 31 int framecnt; 32 AVRational fps; 33 int frame; 34 int next_frame; 35 int next_framesz; 36 int video_stream_index; 37 int audio_stream_index; 38 int compcount; 39 unsigned char components[16]; 40 AVStream* vst; 41 int has_audio; 42 int audiosize; 43} ThpDemuxContext; 44 45 46static int thp_probe(AVProbeData *p) 47{ 48 /* check file header */ 49 if (AV_RL32(p->buf) == MKTAG('T', 'H', 'P', '\0')) 50 return AVPROBE_SCORE_MAX; 51 else 52 return 0; 53} 54 55static int thp_read_header(AVFormatContext *s, 56 AVFormatParameters *ap) 57{ 58 ThpDemuxContext *thp = s->priv_data; 59 AVStream *st; 60 ByteIOContext *pb = s->pb; 61 int i; 62 63 /* Read the file header. */ 64 get_be32(pb); /* Skip Magic. */ 65 thp->version = get_be32(pb); 66 67 get_be32(pb); /* Max buf size. */ 68 get_be32(pb); /* Max samples. */ 69 70 thp->fps = av_d2q(av_int2flt(get_be32(pb)), INT_MAX); 71 thp->framecnt = get_be32(pb); 72 thp->first_framesz = get_be32(pb); 73 get_be32(pb); /* Data size. */ 74 75 thp->compoff = get_be32(pb); 76 get_be32(pb); /* offsetDataOffset. */ 77 thp->first_frame = get_be32(pb); 78 thp->last_frame = get_be32(pb); 79 80 thp->next_framesz = thp->first_framesz; 81 thp->next_frame = thp->first_frame; 82 83 /* Read the component structure. */ 84 url_fseek (pb, thp->compoff, SEEK_SET); 85 thp->compcount = get_be32(pb); 86 87 /* Read the list of component types. */ 88 get_buffer(pb, thp->components, 16); 89 90 for (i = 0; i < thp->compcount; i++) { 91 if (thp->components[i] == 0) { 92 if (thp->vst != 0) 93 break; 94 95 /* Video component. */ 96 st = av_new_stream(s, 0); 97 if (!st) 98 return AVERROR(ENOMEM); 99 100 /* The denominator and numerator are switched because 1/fps 101 is required. */ 102 av_set_pts_info(st, 64, thp->fps.den, thp->fps.num); 103 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 104 st->codec->codec_id = CODEC_ID_THP; 105 st->codec->codec_tag = 0; /* no fourcc */ 106 st->codec->width = get_be32(pb); 107 st->codec->height = get_be32(pb); 108 st->codec->sample_rate = av_q2d(thp->fps); 109 thp->vst = st; 110 thp->video_stream_index = st->index; 111 112 if (thp->version == 0x11000) 113 get_be32(pb); /* Unknown. */ 114 } else if (thp->components[i] == 1) { 115 if (thp->has_audio != 0) 116 break; 117 118 /* Audio component. */ 119 st = av_new_stream(s, 0); 120 if (!st) 121 return AVERROR(ENOMEM); 122 123 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 124 st->codec->codec_id = CODEC_ID_ADPCM_THP; 125 st->codec->codec_tag = 0; /* no fourcc */ 126 st->codec->channels = get_be32(pb); /* numChannels. */ 127 st->codec->sample_rate = get_be32(pb); /* Frequency. */ 128 129 av_set_pts_info(st, 64, 1, st->codec->sample_rate); 130 131 thp->audio_stream_index = st->index; 132 thp->has_audio = 1; 133 } 134 } 135 136 return 0; 137} 138 139static int thp_read_packet(AVFormatContext *s, 140 AVPacket *pkt) 141{ 142 ThpDemuxContext *thp = s->priv_data; 143 ByteIOContext *pb = s->pb; 144 int size; 145 int ret; 146 147 if (thp->audiosize == 0) { 148 /* Terminate when last frame is reached. */ 149 if (thp->frame >= thp->framecnt) 150 return AVERROR(EIO); 151 152 url_fseek(pb, thp->next_frame, SEEK_SET); 153 154 /* Locate the next frame and read out its size. */ 155 thp->next_frame += thp->next_framesz; 156 thp->next_framesz = get_be32(pb); 157 158 get_be32(pb); /* Previous total size. */ 159 size = get_be32(pb); /* Total size of this frame. */ 160 161 /* Store the audiosize so the next time this function is called, 162 the audio can be read. */ 163 if (thp->has_audio) 164 thp->audiosize = get_be32(pb); /* Audio size. */ 165 else 166 thp->frame++; 167 168 ret = av_get_packet(pb, pkt, size); 169 if (ret != size) { 170 av_free_packet(pkt); 171 return AVERROR(EIO); 172 } 173 174 pkt->stream_index = thp->video_stream_index; 175 } else { 176 ret = av_get_packet(pb, pkt, thp->audiosize); 177 if (ret != thp->audiosize) { 178 av_free_packet(pkt); 179 return AVERROR(EIO); 180 } 181 182 pkt->stream_index = thp->audio_stream_index; 183 thp->audiosize = 0; 184 thp->frame++; 185 } 186 187 return 0; 188} 189 190AVInputFormat thp_demuxer = { 191 "thp", 192 NULL_IF_CONFIG_SMALL("THP"), 193 sizeof(ThpDemuxContext), 194 thp_probe, 195 thp_read_header, 196 thp_read_packet 197}; 198