1/*
2 * Creative Voice File muxer.
3 * Copyright (c) 2006  Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * This file is part of FFmpeg.
6 *
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.
11 *
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.
16 *
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
20 */
21
22#include "voc.h"
23
24
25typedef struct voc_enc_context {
26    int param_written;
27} VocEncContext;
28
29static int voc_write_header(AVFormatContext *s)
30{
31    ByteIOContext *pb = s->pb;
32    const int header_size = 26;
33    const int version = 0x0114;
34
35    if (s->nb_streams != 1
36        || s->streams[0]->codec->codec_type != CODEC_TYPE_AUDIO)
37        return AVERROR_PATCHWELCOME;
38
39    put_buffer(pb, ff_voc_magic, sizeof(ff_voc_magic) - 1);
40    put_le16(pb, header_size);
41    put_le16(pb, version);
42    put_le16(pb, ~version + 0x1234);
43
44    return 0;
45}
46
47static int voc_write_packet(AVFormatContext *s, AVPacket *pkt)
48{
49    VocEncContext *voc = s->priv_data;
50    AVCodecContext *enc = s->streams[0]->codec;
51    ByteIOContext *pb = s->pb;
52
53    if (!voc->param_written) {
54        if (enc->codec_tag > 0xFF) {
55            put_byte(pb, VOC_TYPE_NEW_VOICE_DATA);
56            put_le24(pb, pkt->size + 12);
57            put_le32(pb, enc->sample_rate);
58            put_byte(pb, enc->bits_per_coded_sample);
59            put_byte(pb, enc->channels);
60            put_le16(pb, enc->codec_tag);
61            put_le32(pb, 0);
62        } else {
63            if (s->streams[0]->codec->channels > 1) {
64                put_byte(pb, VOC_TYPE_EXTENDED);
65                put_le24(pb, 4);
66                put_le16(pb, 65536-256000000/(enc->sample_rate*enc->channels));
67                put_byte(pb, enc->codec_tag);
68                put_byte(pb, enc->channels - 1);
69            }
70            put_byte(pb, VOC_TYPE_VOICE_DATA);
71            put_le24(pb, pkt->size + 2);
72            put_byte(pb, 256 - 1000000 / enc->sample_rate);
73            put_byte(pb, enc->codec_tag);
74        }
75        voc->param_written = 1;
76    } else {
77        put_byte(pb, VOC_TYPE_VOICE_DATA_CONT);
78        put_le24(pb, pkt->size);
79    }
80
81    put_buffer(pb, pkt->data, pkt->size);
82    return 0;
83}
84
85static int voc_write_trailer(AVFormatContext *s)
86{
87    put_byte(s->pb, 0);
88    return 0;
89}
90
91AVOutputFormat voc_muxer = {
92    "voc",
93    NULL_IF_CONFIG_SMALL("Creative Voice file format"),
94    "audio/x-voc",
95    "voc",
96    sizeof(VocEncContext),
97    CODEC_ID_PCM_U8,
98    CODEC_ID_NONE,
99    voc_write_header,
100    voc_write_packet,
101    voc_write_trailer,
102    .codec_tag=(const AVCodecTag* const []){ff_voc_codec_tags, 0},
103};
104