3 * Copyright (c) 2007 Marco Gerards
5 * This file is part of Libav.
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.
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.
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
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/intfloat.h"
27 typedef struct ThpDemuxContext
{
38 int video_stream_index
;
39 int audio_stream_index
;
41 unsigned char components
[16];
48 static int thp_probe(AVProbeData
*p
)
50 /* check file header */
51 if (AV_RL32(p
->buf
) == MKTAG('T', 'H', 'P', '\0'))
52 return AVPROBE_SCORE_MAX
;
57 static int thp_read_header(AVFormatContext
*s
)
59 ThpDemuxContext
*thp
= s
->priv_data
;
61 AVIOContext
*pb
= s
->pb
;
64 /* Read the file header. */
65 avio_rb32(pb
); /* Skip Magic. */
66 thp
->version
= avio_rb32(pb
);
68 avio_rb32(pb
); /* Max buf size. */
69 avio_rb32(pb
); /* Max samples. */
71 thp
->fps
= av_d2q(av_int2float(avio_rb32(pb
)), INT_MAX
);
72 thp
->framecnt
= avio_rb32(pb
);
73 thp
->first_framesz
= avio_rb32(pb
);
74 avio_rb32(pb
); /* Data size. */
76 thp
->compoff
= avio_rb32(pb
);
77 avio_rb32(pb
); /* offsetDataOffset. */
78 thp
->first_frame
= avio_rb32(pb
);
79 thp
->last_frame
= avio_rb32(pb
);
81 thp
->next_framesz
= thp
->first_framesz
;
82 thp
->next_frame
= thp
->first_frame
;
84 /* Read the component structure. */
85 avio_seek (pb
, thp
->compoff
, SEEK_SET
);
86 thp
->compcount
= avio_rb32(pb
);
88 /* Read the list of component types. */
89 avio_read(pb
, thp
->components
, 16);
91 for (i
= 0; i
< thp
->compcount
; i
++) {
92 if (thp
->components
[i
] == 0) {
96 /* Video component. */
97 st
= avformat_new_stream(s
, NULL
);
99 return AVERROR(ENOMEM
);
101 /* The denominator and numerator are switched because 1/fps
103 avpriv_set_pts_info(st
, 64, thp
->fps
.den
, thp
->fps
.num
);
104 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
105 st
->codec
->codec_id
= AV_CODEC_ID_THP
;
106 st
->codec
->codec_tag
= 0; /* no fourcc */
107 st
->codec
->width
= avio_rb32(pb
);
108 st
->codec
->height
= avio_rb32(pb
);
109 st
->codec
->sample_rate
= av_q2d(thp
->fps
);
111 thp
->video_stream_index
= st
->index
;
113 if (thp
->version
== 0x11000)
114 avio_rb32(pb
); /* Unknown. */
115 } else if (thp
->components
[i
] == 1) {
116 if (thp
->has_audio
!= 0)
119 /* Audio component. */
120 st
= avformat_new_stream(s
, NULL
);
122 return AVERROR(ENOMEM
);
124 st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
125 st
->codec
->codec_id
= AV_CODEC_ID_ADPCM_THP
;
126 st
->codec
->codec_tag
= 0; /* no fourcc */
127 st
->codec
->channels
= avio_rb32(pb
); /* numChannels. */
128 st
->codec
->sample_rate
= avio_rb32(pb
); /* Frequency. */
130 avpriv_set_pts_info(st
, 64, 1, st
->codec
->sample_rate
);
132 thp
->audio_stream_index
= st
->index
;
140 static int thp_read_packet(AVFormatContext
*s
,
143 ThpDemuxContext
*thp
= s
->priv_data
;
144 AVIOContext
*pb
= s
->pb
;
148 if (thp
->audiosize
== 0) {
149 /* Terminate when last frame is reached. */
150 if (thp
->frame
>= thp
->framecnt
)
153 avio_seek(pb
, thp
->next_frame
, SEEK_SET
);
155 /* Locate the next frame and read out its size. */
156 thp
->next_frame
+= thp
->next_framesz
;
157 thp
->next_framesz
= avio_rb32(pb
);
159 avio_rb32(pb
); /* Previous total size. */
160 size
= avio_rb32(pb
); /* Total size of this frame. */
162 /* Store the audiosize so the next time this function is called,
163 the audio can be read. */
165 thp
->audiosize
= avio_rb32(pb
); /* Audio size. */
169 ret
= av_get_packet(pb
, pkt
, size
);
175 pkt
->stream_index
= thp
->video_stream_index
;
177 ret
= av_get_packet(pb
, pkt
, thp
->audiosize
);
178 if (ret
!= thp
->audiosize
) {
183 pkt
->stream_index
= thp
->audio_stream_index
;
184 if (thp
->audiosize
>= 8)
185 pkt
->duration
= AV_RB32(&pkt
->data
[4]);
194 AVInputFormat ff_thp_demuxer
= {
196 .long_name
= NULL_IF_CONFIG_SMALL("THP"),
197 .priv_data_size
= sizeof(ThpDemuxContext
),
198 .read_probe
= thp_probe
,
199 .read_header
= thp_read_header
,
200 .read_packet
= thp_read_packet