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