xref: /third_party/ffmpeg/libavformat/thp.c (revision cabdff1a)
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