1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * THP Demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2007 Marco Gerards 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 23cabdff1aSopenharmony_ci#include "libavutil/intfloat.h" 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "avio_internal.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_citypedef struct ThpDemuxContext { 29cabdff1aSopenharmony_ci int version; 30cabdff1aSopenharmony_ci unsigned first_frame; 31cabdff1aSopenharmony_ci unsigned first_framesz; 32cabdff1aSopenharmony_ci unsigned last_frame; 33cabdff1aSopenharmony_ci int compoff; 34cabdff1aSopenharmony_ci unsigned framecnt; 35cabdff1aSopenharmony_ci AVRational fps; 36cabdff1aSopenharmony_ci unsigned frame; 37cabdff1aSopenharmony_ci int64_t next_frame; 38cabdff1aSopenharmony_ci unsigned next_framesz; 39cabdff1aSopenharmony_ci int video_stream_index; 40cabdff1aSopenharmony_ci int audio_stream_index; 41cabdff1aSopenharmony_ci int compcount; 42cabdff1aSopenharmony_ci unsigned char components[16]; 43cabdff1aSopenharmony_ci AVStream* vst; 44cabdff1aSopenharmony_ci int has_audio; 45cabdff1aSopenharmony_ci unsigned audiosize; 46cabdff1aSopenharmony_ci} ThpDemuxContext; 47cabdff1aSopenharmony_ci 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_cistatic int thp_probe(const AVProbeData *p) 50cabdff1aSopenharmony_ci{ 51cabdff1aSopenharmony_ci double d; 52cabdff1aSopenharmony_ci /* check file header */ 53cabdff1aSopenharmony_ci if (AV_RL32(p->buf) != MKTAG('T', 'H', 'P', '\0')) 54cabdff1aSopenharmony_ci return 0; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci d = av_int2float(AV_RB32(p->buf + 16)); 57cabdff1aSopenharmony_ci if (d < 0.1 || d > 1000 || isnan(d)) 58cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX/4; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 61cabdff1aSopenharmony_ci} 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_cistatic int thp_read_header(AVFormatContext *s) 64cabdff1aSopenharmony_ci{ 65cabdff1aSopenharmony_ci ThpDemuxContext *thp = s->priv_data; 66cabdff1aSopenharmony_ci AVStream *st; 67cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 68cabdff1aSopenharmony_ci int64_t fsize= avio_size(pb); 69cabdff1aSopenharmony_ci uint32_t maxsize; 70cabdff1aSopenharmony_ci int i; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci /* Read the file header. */ 73cabdff1aSopenharmony_ci avio_rb32(pb); /* Skip Magic. */ 74cabdff1aSopenharmony_ci thp->version = avio_rb32(pb); 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci avio_rb32(pb); /* Max buf size. */ 77cabdff1aSopenharmony_ci avio_rb32(pb); /* Max samples. */ 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci thp->fps = av_d2q(av_int2float(avio_rb32(pb)), INT_MAX); 80cabdff1aSopenharmony_ci if (thp->fps.den <= 0 || thp->fps.num < 0) 81cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 82cabdff1aSopenharmony_ci thp->framecnt = avio_rb32(pb); 83cabdff1aSopenharmony_ci thp->first_framesz = avio_rb32(pb); 84cabdff1aSopenharmony_ci maxsize = avio_rb32(pb); 85cabdff1aSopenharmony_ci if (fsize > 0 && (!maxsize || fsize < maxsize)) 86cabdff1aSopenharmony_ci maxsize = fsize; 87cabdff1aSopenharmony_ci ffiocontext(pb)->maxsize = fsize; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci thp->compoff = avio_rb32(pb); 90cabdff1aSopenharmony_ci avio_rb32(pb); /* offsetDataOffset. */ 91cabdff1aSopenharmony_ci thp->first_frame = avio_rb32(pb); 92cabdff1aSopenharmony_ci thp->last_frame = avio_rb32(pb); 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci thp->next_framesz = thp->first_framesz; 95cabdff1aSopenharmony_ci thp->next_frame = thp->first_frame; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci /* Read the component structure. */ 98cabdff1aSopenharmony_ci avio_seek (pb, thp->compoff, SEEK_SET); 99cabdff1aSopenharmony_ci thp->compcount = avio_rb32(pb); 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci if (thp->compcount > FF_ARRAY_ELEMS(thp->components)) 102cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci /* Read the list of component types. */ 105cabdff1aSopenharmony_ci avio_read(pb, thp->components, 16); 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci for (i = 0; i < thp->compcount; i++) { 108cabdff1aSopenharmony_ci if (thp->components[i] == 0) { 109cabdff1aSopenharmony_ci if (thp->vst) 110cabdff1aSopenharmony_ci break; 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci /* Video component. */ 113cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 114cabdff1aSopenharmony_ci if (!st) 115cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci /* The denominator and numerator are switched because 1/fps 118cabdff1aSopenharmony_ci is required. */ 119cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, thp->fps.den, thp->fps.num); 120cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 121cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_THP; 122cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no fourcc */ 123cabdff1aSopenharmony_ci st->codecpar->width = avio_rb32(pb); 124cabdff1aSopenharmony_ci st->codecpar->height = avio_rb32(pb); 125cabdff1aSopenharmony_ci st->codecpar->sample_rate = av_q2d(thp->fps); 126cabdff1aSopenharmony_ci st->nb_frames = 127cabdff1aSopenharmony_ci st->duration = thp->framecnt; 128cabdff1aSopenharmony_ci thp->vst = st; 129cabdff1aSopenharmony_ci thp->video_stream_index = st->index; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci if (thp->version == 0x11000) 132cabdff1aSopenharmony_ci avio_rb32(pb); /* Unknown. */ 133cabdff1aSopenharmony_ci } else if (thp->components[i] == 1) { 134cabdff1aSopenharmony_ci if (thp->has_audio != 0) 135cabdff1aSopenharmony_ci break; 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci /* Audio component. */ 138cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 139cabdff1aSopenharmony_ci if (!st) 140cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 143cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ADPCM_THP; 144cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no fourcc */ 145cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels = avio_rb32(pb); 146cabdff1aSopenharmony_ci st->codecpar->sample_rate = avio_rb32(pb); /* Frequency. */ 147cabdff1aSopenharmony_ci st->duration = avio_rb32(pb); 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci thp->audio_stream_index = st->index; 152cabdff1aSopenharmony_ci thp->has_audio = 1; 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci } 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci if (!thp->vst) 157cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci return 0; 160cabdff1aSopenharmony_ci} 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_cistatic int thp_read_packet(AVFormatContext *s, 163cabdff1aSopenharmony_ci AVPacket *pkt) 164cabdff1aSopenharmony_ci{ 165cabdff1aSopenharmony_ci ThpDemuxContext *thp = s->priv_data; 166cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 167cabdff1aSopenharmony_ci unsigned int size; 168cabdff1aSopenharmony_ci int ret; 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci if (thp->audiosize == 0) { 171cabdff1aSopenharmony_ci /* Terminate when last frame is reached. */ 172cabdff1aSopenharmony_ci if (thp->frame >= thp->framecnt) 173cabdff1aSopenharmony_ci return AVERROR_EOF; 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci avio_seek(pb, thp->next_frame, SEEK_SET); 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci /* Locate the next frame and read out its size. */ 178cabdff1aSopenharmony_ci thp->next_frame += FFMAX(thp->next_framesz, 1); 179cabdff1aSopenharmony_ci thp->next_framesz = avio_rb32(pb); 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci avio_rb32(pb); /* Previous total size. */ 182cabdff1aSopenharmony_ci size = avio_rb32(pb); /* Total size of this frame. */ 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci /* Store the audiosize so the next time this function is called, 185cabdff1aSopenharmony_ci the audio can be read. */ 186cabdff1aSopenharmony_ci if (thp->has_audio) 187cabdff1aSopenharmony_ci thp->audiosize = avio_rb32(pb); /* Audio size. */ 188cabdff1aSopenharmony_ci else 189cabdff1aSopenharmony_ci thp->frame++; 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, size); 192cabdff1aSopenharmony_ci if (ret < 0) 193cabdff1aSopenharmony_ci return ret; 194cabdff1aSopenharmony_ci if (ret != size) { 195cabdff1aSopenharmony_ci return AVERROR(EIO); 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci pkt->stream_index = thp->video_stream_index; 199cabdff1aSopenharmony_ci } else { 200cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, thp->audiosize); 201cabdff1aSopenharmony_ci if (ret < 0) 202cabdff1aSopenharmony_ci return ret; 203cabdff1aSopenharmony_ci if (ret != thp->audiosize) { 204cabdff1aSopenharmony_ci return AVERROR(EIO); 205cabdff1aSopenharmony_ci } 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci pkt->stream_index = thp->audio_stream_index; 208cabdff1aSopenharmony_ci if (thp->audiosize >= 8) 209cabdff1aSopenharmony_ci pkt->duration = AV_RB32(&pkt->data[4]); 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci thp->audiosize = 0; 212cabdff1aSopenharmony_ci thp->frame++; 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci return 0; 216cabdff1aSopenharmony_ci} 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ciconst AVInputFormat ff_thp_demuxer = { 219cabdff1aSopenharmony_ci .name = "thp", 220cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("THP"), 221cabdff1aSopenharmony_ci .priv_data_size = sizeof(ThpDemuxContext), 222cabdff1aSopenharmony_ci .read_probe = thp_probe, 223cabdff1aSopenharmony_ci .read_header = thp_read_header, 224cabdff1aSopenharmony_ci .read_packet = thp_read_packet 225cabdff1aSopenharmony_ci}; 226