2 * Creative Voice File demuxer.
3 * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
5 * This file is part of FFmpeg.
7 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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(const 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
;
48 header_size
= avio_rl16(pb
) - 22;
49 if (header_size
!= 4) {
50 av_log(s
, AV_LOG_ERROR
, "unknown header size: %d\n", header_size
);
51 return AVERROR(ENOSYS
);
53 avio_skip(pb
, header_size
);
55 s
->ctx_flags
|= AVFMTCTX_NOHEADER
;
57 voc
->remaining_size
= 0;
61 static int voc_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
64 AVStream
*st
= avformat_new_stream(s
, NULL
);
66 return AVERROR(ENOMEM
);
67 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
69 return ff_voc_get_packet(s
, pkt
, s
->streams
[0], 0);
72 static int voc_read_seek(AVFormatContext
*s
, int stream_index
,
73 int64_t timestamp
, int flags
)
75 VocDecContext
*voc
= s
->priv_data
;
80 if (s
->nb_streams
< 1) {
81 av_log(s
, AV_LOG_ERROR
, "cannot seek while no stream was found yet\n");
82 return AVERROR(EINVAL
);
85 st
= s
->streams
[stream_index
];
87 index
= av_index_search_timestamp(st
, timestamp
, flags
);
89 if (index
>= 0 && index
< sti
->nb_index_entries
- 1) {
90 const AVIndexEntry
*const e
= &sti
->index_entries
[index
];
91 avio_seek(s
->pb
, e
->pos
, SEEK_SET
);
92 voc
->pts
= e
->timestamp
;
93 voc
->remaining_size
= e
->size
;
95 } else if (sti
->nb_index_entries
&& sti
->index_entries
[0].timestamp
<= timestamp
) {
96 const AVIndexEntry
*const e
= &sti
->index_entries
[sti
->nb_index_entries
- 1];
97 // prepare context for seek_frame_generic()
98 voc
->pts
= e
->timestamp
;
99 voc
->remaining_size
= e
->size
;
104 const FFInputFormat ff_voc_demuxer
= {
106 .p
.long_name
= NULL_IF_CONFIG_SMALL("Creative Voice"),
107 .p
.codec_tag
= ff_voc_codec_tags_list
,
108 .priv_data_size
= sizeof(VocDecContext
),
109 .read_probe
= voc_probe
,
110 .read_header
= voc_read_header
,
111 .read_packet
= voc_read_packet
,
112 .read_seek
= voc_read_seek
,