2 * Creative Voice File demuxer.
3 * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
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"
27 static int voc_probe(AVProbeData
*p
)
31 if (memcmp(p
->buf
, ff_voc_magic
, sizeof(ff_voc_magic
) - 1))
33 version
= AV_RL16(p
->buf
+ 22);
34 check
= AV_RL16(p
->buf
+ 24);
35 if (~version
+ 0x1234 != check
)
38 return AVPROBE_SCORE_MAX
;
41 static int voc_read_header(AVFormatContext
*s
)
43 VocDecContext
*voc
= s
->priv_data
;
44 AVIOContext
*pb
= s
->pb
;
49 header_size
= avio_rl16(pb
) - 22;
50 if (header_size
!= 4) {
51 av_log(s
, AV_LOG_ERROR
, "unknown header size: %d\n", header_size
);
52 return AVERROR(ENOSYS
);
54 avio_skip(pb
, header_size
);
55 st
= avformat_new_stream(s
, NULL
);
57 return AVERROR(ENOMEM
);
58 st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
60 voc
->remaining_size
= 0;
65 ff_voc_get_packet(AVFormatContext
*s
, AVPacket
*pkt
, AVStream
*st
, int max_size
)
67 VocDecContext
*voc
= s
->priv_data
;
68 AVCodecContext
*dec
= st
->codec
;
69 AVIOContext
*pb
= s
->pb
;
71 int size
, tmp_codec
=-1;
75 while (!voc
->remaining_size
) {
77 if (type
== VOC_TYPE_EOF
)
79 voc
->remaining_size
= avio_rl24(pb
);
80 if (!voc
->remaining_size
) {
83 voc
->remaining_size
= avio_size(pb
) - avio_tell(pb
);
88 case VOC_TYPE_VOICE_DATA
:
89 if (!dec
->sample_rate
) {
90 dec
->sample_rate
= 1000000 / (256 - avio_r8(pb
));
92 dec
->sample_rate
= sample_rate
;
93 avpriv_set_pts_info(st
, 64, 1, dec
->sample_rate
);
96 dec
->channels
= channels
;
97 tmp_codec
= avio_r8(pb
);
98 dec
->bits_per_coded_sample
= av_get_bits_per_sample(dec
->codec_id
);
99 voc
->remaining_size
-= 2;
104 case VOC_TYPE_VOICE_DATA_CONT
:
107 case VOC_TYPE_EXTENDED
:
108 sample_rate
= avio_rl16(pb
);
110 channels
= avio_r8(pb
) + 1;
111 sample_rate
= 256000000 / (channels
* (65536 - sample_rate
));
112 voc
->remaining_size
= 0;
116 case VOC_TYPE_NEW_VOICE_DATA
:
117 if (!dec
->sample_rate
) {
118 dec
->sample_rate
= avio_rl32(pb
);
119 avpriv_set_pts_info(st
, 64, 1, dec
->sample_rate
);
122 dec
->bits_per_coded_sample
= avio_r8(pb
);
123 dec
->channels
= avio_r8(pb
);
124 tmp_codec
= avio_rl16(pb
);
126 voc
->remaining_size
-= 12;
131 avio_skip(pb
, voc
->remaining_size
);
132 max_size
-= voc
->remaining_size
;
133 voc
->remaining_size
= 0;
138 if (tmp_codec
>= 0) {
139 tmp_codec
= ff_codec_get_id(ff_voc_codec_tags
, tmp_codec
);
140 if (dec
->codec_id
== AV_CODEC_ID_NONE
)
141 dec
->codec_id
= tmp_codec
;
142 else if (dec
->codec_id
!= tmp_codec
)
143 av_log(s
, AV_LOG_WARNING
, "Ignoring mid-stream change in audio codec\n");
144 if (dec
->codec_id
== AV_CODEC_ID_NONE
) {
145 if (s
->audio_codec_id
== AV_CODEC_ID_NONE
) {
146 av_log(s
, AV_LOG_ERROR
, "unknown codec tag\n");
147 return AVERROR(EINVAL
);
149 av_log(s
, AV_LOG_WARNING
, "unknown codec tag\n");
153 dec
->bit_rate
= dec
->sample_rate
* dec
->bits_per_coded_sample
;
157 size
= FFMIN(voc
->remaining_size
, max_size
);
158 voc
->remaining_size
-= size
;
159 return av_get_packet(pb
, pkt
, size
);
162 static int voc_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
164 return ff_voc_get_packet(s
, pkt
, s
->streams
[0], 0);
167 AVInputFormat ff_voc_demuxer
= {
169 .long_name
= NULL_IF_CONFIG_SMALL("Creative Voice"),
170 .priv_data_size
= sizeof(VocDecContext
),
171 .read_probe
= voc_probe
,
172 .read_header
= voc_read_header
,
173 .read_packet
= voc_read_packet
,
174 .codec_tag
= (const AVCodecTag
* const []){ ff_voc_codec_tags
, 0 },