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